First version. ADHERE service support with label, banner and media ads.
[qtmads] / src / qtmadsservice.cpp
1 /*
2  * Copyright (c) 2009 Eetu Lehmusvuo.
3  *
4  * This file is part of QtMAds.
5  *
6  * QtMAds is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * QtMAds is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with QtMAds.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "qtmadsservice.h"
22
23 #include <QHttp>
24 #include <QUrl>
25 #include <QDebug>
26 #include <QImage>
27 #include <QFile>
28 #include <QXmlStreamReader>
29 #include <QDir>
30 #include <QPluginLoader>
31
32 QtmadsService::QtmadsService()
33 {
34 }
35
36 QtmadsService::~QtmadsService()
37 {
38     http->close();
39     delete http;
40 }
41
42 bool QtmadsService::initializeService(QString service, quint32 adGroup, AdType defaultAdType)
43 {
44     this->serviceName = service;
45     this->adGroupId = adGroup;
46     this->defAdType = defaultAdType;
47
48     bool parseSuccess = true;
49     // ../plugins/SERVICE_NAME_adconfigure.xml
50     QFile file(CONF_PATH + this->serviceName + CONF_FILE_POSTFIX );
51     parseSuccess = file.exists();
52
53     /*if(!file.exists()){
54         // ./default_adconfigure.xml
55         file.setFileName("." + CONF_FILE);
56         parseSuccess = file.exists();
57     }*/
58
59     if(parseSuccess){
60         file.open(QIODevice::ReadOnly);
61         this->parseXmlConfFile(file);
62     }
63
64     if(parseSuccess){
65         initialized = true;
66     }else{
67         qDebug() << "Ad service configure failed. " << CONF_PATH + this->serviceName + CONF_FILE_POSTFIX ;
68         initialized = false;
69         //TODO: parse failed
70     }
71
72     return isInitialized();
73 }
74
75 bool QtmadsService::isInitialized()
76 {
77     return initialized;
78 }
79
80 void QtmadsService::getAd(QHash<QString, QVariant> &adParameters)
81 {
82     //qDebug() << "QtmadsService::getAd()";
83     if(isInitialized()){
84         QList<QPair<QString,QString> > parameters;
85         this->parseUrlParameters(adParameters, parameters);
86
87         QUrl url(this->serviceUrl);
88         url.setQueryItems(parameters);
89         QByteArray path = QUrl::toPercentEncoding(url.path(), "!$&'()*+,;=:@/?");
90         if (path.isEmpty())
91             path = "/";
92         path.append(QUrl::toPercentEncoding("?", "!$&'()*+,;=:@/?"));
93         path.append(url.encodedQuery());
94
95         http = new QHttp(this);
96         connect(http, SIGNAL(requestFinished(int, bool)), this, SLOT(adRequestFinished(int, bool)));
97         http->setHost(url.host());
98         //qDebug() << "Url: " <<  url.toString();
99         adTrasactionId = http->get(path);
100     }else{
101         emit adRequestFailed();
102     }
103 }
104
105
106 void QtmadsService::adRequestFinished(int transactionId, bool error)
107 {
108     //qDebug() << "adRequestFinished()";
109     if(adTrasactionId != transactionId){
110                 return;
111         }
112         adTrasactionId = -1;
113
114         if(!error){
115                 QByteArray data = http->readAll();
116
117                 qDebug() << "Data: " << data;
118
119                 QHash<QString, QVariant> adParams;// = new QHash<QString, QVariant>();
120                 this->parseReceivedAd(data, adParams);
121                 QHash<QString, QVariant>::iterator i;
122
123
124                 /*for(i = adParams.begin(); i !=  adParams.end(); i++){
125                     qDebug() << "key: " << i.key() << " value: " << i.value().toString();
126                 }*/
127
128                 emit adRequestReady(adParams);
129         }else{
130             qDebug() << "adRequestFailed()";
131                 emit adRequestFailed();
132         }
133
134         disconnect(http, SIGNAL(requestFinished(int, bool)), this, SLOT(adRequestFinished(int, bool)));
135 }
136
137 void QtmadsService::getRemoteImage(QString urlString)
138 {
139     QUrl url(urlString);
140     QByteArray path = QUrl::toPercentEncoding(url.path(), "!$&'()*+,;=:@/?");
141     if (path.isEmpty())
142         path = "/";
143
144     connect(http, SIGNAL(requestFinished(int, bool)), this, SLOT(imageRequestFinished(int, bool)));
145     http->setHost(url.host());
146     imageTrasactionId = http->get(path);
147 }
148
149
150 void QtmadsService::imageRequestFinished(int transactionId, bool error)
151 {
152     if(imageTrasactionId != transactionId){
153         return;
154     }
155     imageTrasactionId = -1;
156
157     if(!error){
158         QImage *image = new QImage();
159         if(image->loadFromData(http->readAll())){
160             emit imageRequestReady(image);
161             delete image;
162         }else{
163             delete image;
164             emit imageRequestFailed();
165         }
166     }
167
168     disconnect(http, SIGNAL(requestFinished(int, bool)), this, SLOT(imageRequestFinished(int, bool)));
169 }
170
171
172 void QtmadsService::setDefaultAdType(AdType type)
173 {
174     this->defAdType = type;
175 }
176
177 AdType QtmadsService::defaultAdType()
178 {
179     return this->defAdType;
180 }
181
182 bool QtmadsService::parseXmlConfFile(QFile &file)
183 {
184     qDebug() << "QtmadsService::parseXmlConfFile()";
185     bool success = false;
186     QXmlStreamReader xmlReader(&file);
187
188     while (!xmlReader.atEnd()) {
189         // find right servicename tag
190         if(QXmlStreamReader::StartElement == xmlReader.readNext()
191                 && 0 == xmlReader.name().compare(TAG_SERVICE)
192                 && 0 == xmlReader.attributes().value("name").compare(this->serviceName)){
193             this->serviceUrl.clear();
194             this->serviceUrl.append(xmlReader.attributes().value("url"));
195
196             // until </service>
197             while (!(QXmlStreamReader::EndElement == xmlReader.readNext()
198                     && 0 == xmlReader.name().compare(TAG_SERVICE))) {
199                 success = true;
200
201                 if(QXmlStreamReader::StartElement == xmlReader.tokenType()){
202                     if(0 == xmlReader.name().compare(TAG_ACCOUNTID)){
203                         parameterTags.insert(
204                                 QString(TAG_ACCOUNTID),xmlReader.attributes().value(TAG_KEY).toString());
205                         this->accountId.clear();
206                         this->accountId.append(xmlReader.attributes().value(TAG_VALUE));
207                     }else if(0 == xmlReader.name().compare(TAG_PASSWORD)){
208                         parameterTags.insert(
209                                 QString(TAG_PASSWORD),xmlReader.attributes().value(TAG_KEY).toString());
210                         this->password.clear();
211                         this->password.append(xmlReader.attributes().value(TAG_VALUE));
212                     }else if(0 == xmlReader.name().compare(TAG_CAMPAIGN)){
213
214                         if(0 == xmlReader.attributes().value("id").compare(QString("%1").arg(this->adGroupId))){
215                             // until </campaign>
216                             while(!(QXmlStreamReader::EndElement == xmlReader.readNext()
217                                     && 0 == xmlReader.name().compare(TAG_CAMPAIGN))){
218                                 if(QXmlStreamReader::StartElement == xmlReader.tokenType()){
219                                     /*qDebug() << "name: " << xmlReader.name()
220                                         << "key: " << xmlReader.attributes().value(TAG_KEY).toString()
221                                         << "value: " << xmlReader.attributes().value(TAG_VALUE).toString();*/
222                                     if(0 == xmlReader.name().compare(TAG_ADTYPE)){
223                                         parameterTags.insert(
224                                                 QString(TAG_ADTYPE),xmlReader.attributes().value(TAG_KEY).toString());
225                                         this->defAdType = this->getAdTypeFromString(xmlReader.attributes().value(TAG_VALUE).toString());
226
227                                     }else if(0 == xmlReader.name().compare(TAG_LANGUAGE)){
228                                         parameterTags.insert(
229                                                 QString(TAG_LANGUAGE),xmlReader.attributes().value(TAG_KEY).toString());
230                                         this->language = xmlReader.attributes().value(TAG_VALUE).toString();
231
232                                     }else if(0 == xmlReader.name().compare(TAG_TRANSACTIONID)){
233                                         parameterTags.insert(
234                                                 QString(TAG_TRANSACTIONID),xmlReader.attributes().value(TAG_KEY).toString());
235                                         this->transactionId = xmlReader.attributes().value(TAG_VALUE).toString();
236
237                                     }else{
238                                         qDebug() << "Unknown element: " << xmlReader.tokenString();
239                                         if(xmlReader.atEnd()){
240                                             // TODO: throw exception?
241                                             qDebug() << "Unexpected end of document!";
242                                             return false;
243                                         }
244
245                                     }
246                                 }
247                             }
248                         }
249                     }else{
250                         qDebug() << "Unknown element: " << xmlReader.tokenString();
251                         if(xmlReader.atEnd()){
252                             // TODO: throw exception?
253                             qDebug() << "Unexpected end of document!";
254                             return false;
255                         }
256                     }
257                 }
258             }
259         }
260     }
261
262     /*while (!xmlReader.atEnd()) {
263     qDebug() << "Type: "<< xmlReader.readNext();
264     qDebug() << " Tokenstring: " << xmlReader.tokenString();
265     qDebug() << " name: " << xmlReader.name(); //<< " key: " << xmlReader.attributes().value("key") << " value: " << xmlReader.attributes().value("value");
266     qDebug() << " ";
267     }*/
268
269     return success;
270 }
271
272 AdType QtmadsService::getAdTypeFromString(QString adStr)
273 {
274     AdType adType = anyAd;
275
276     if(0 == adStr.compare("txtAd")){
277         adType = txtAd;
278     }else if(0 == adStr.compare("imageAd")){
279         adType = imageAd;
280     }else if(0 == adStr.compare("txtBannerAd")){
281         adType = txtBannerAd;
282     }else if(0 == adStr.compare("imageBannerAd")){
283         adType = imageBannerAd;
284     }else if(0 == adStr.compare("audioAd")){
285         adType = audioAd;
286     }else if(0 == adStr.compare("videoAd")){
287         adType = videoAd;
288     }
289     return adType;
290 }
291
292 QString QtmadsService::getStringFromAdType(AdType adType)
293 {
294     QString adStr;
295     switch(adType){
296         default:
297         case anyAd:
298             adStr.append("anyAd");
299             break;
300         case txtAd:
301             adStr.append("txtAd");
302             break;
303         case imageAd:
304             adStr.append("imageAd");
305             break;
306         case txtBannerAd:
307             adStr.append("txtBannerAd");
308             break;
309         case imageBannerAd:
310             adStr.append("imageBannerAd");
311             break;
312         case audioAd:
313             adStr.append("audioAd");
314             break;
315         case videoAd:
316             adStr.append("videoAd");
317             break;
318     }
319     return adStr;
320 }