source: SMSSender/gateways/SwisscomXtraZone/src/business/BCAccount.cpp @ 72:fc91522ef9be

3.0
Last change on this file since 72:fc91522ef9be was 72:fc91522ef9be, checked in by Sämy Zehnder <saemy.zehnder@…>, 12 years ago
  • Started exception handling
  • Fixed several bugs from the removal of the iloginaccount gateway
File size: 10.2 KB
Line 
1/*
2 * BCAccount.cpp
3 *
4 *  Created on: Jul 9, 2009
5 *      Author: saemy
6 */
7#include "BCAccount.h"
8
9#include <algorithm>
10
11#include <QFile>
12#include <QSslCertificate>
13#include <QSslSocket>
14#include <QDebug>
15
16#include <stdexceptions.h>
17#include <loginaccountexceptions.h>
18
19#include <snumber.h>
20#include <typeconvert.h>
21
22#include "BCGateway.h"
23#include "validation/BCAccountValidator.h"
24#include "persistence/DAAccountStorageOfficer.h"
25
26namespace SwisscomXtraZone {
27
28BCAccount::BCAccount(IStorage* storage)
29    : AbstractLoginAccount(new DAAccountStorageOfficer(this, storage), new BCAccountValidator(this))
30
31    , MAX_MOBILE(10)
32{
33    httpHelper_     = new SHttpHelper();
34
35    /* Insert the swisscom-mobile.ch certificate to allow propper loading of the websites... */
36
37    QFile certFile(":/certs/Swisscom_Root_CA_1_pem.crt");
38    Q_ASSERT(certFile.open(QIODevice::ReadOnly));
39    QSslCertificate cert(&certFile, QSsl::Pem);
40    // this replaces the internal QTcpSocket QHttp uses; unfortunately
41    // we cannot reuse that one because Qt does not provide an accessor
42    // for it
43    QHttp* http = httpHelper_->http();
44    QSslSocket* sslSocket = new QSslSocket(http);
45    sslSocket->addCaCertificate(cert);
46    http->setSocket(sslSocket);
47}
48
49BCAccount::~BCAccount(){
50    delete getStorageOfficer();
51    delete getValidator();
52    delete httpHelper_;
53}
54
55IAccount* BCAccount::getClonedInstance() const {
56    return new BCAccount(getStorageOfficer()->storage());
57}
58
59
60AbstractLoginGateway* BCAccount::gateway() const {
61    return BCGateway::instance();
62}
63
64
65void BCAccount::doInitialize() {
66    login();
67    _parseMainPage();
68    logout();
69}
70
71
72void BCAccount::cancelSMSSending() {
73    //TODO: implement this...
74}
75
76
77
78void BCAccount::doLogin() {
79    qDebug() << "Starting login";
80
81    QMap<QString, QString> posts;
82    posts.insert("isiwebuserid", username());
83    posts.insert("isiwebpasswd", password());
84
85    if (!httpHelper_->post(LOGIN_PAGE, lastHtml_, QMap<QString, QString>(), posts)) {
86        throw LoginAccount::ELoginException(LoginAccount::ELoginException::RequestError).chain(httpHelper_->lastError());
87    }
88
89    if (lastHtml_.contains("Begin error region content", Qt::CaseInsensitive)) {
90        throw LoginAccount::ELoginException(LoginAccount::ELoginException::InvalidLoginData).chain(httpHelper_->lastError());
91    }
92
93    if (!lastHtml_.contains("CobYouthSMSSenden:txtMessage", Qt::CaseInsensitive)) {
94        throw LoginAccount::ELoginException("The returned page contains no message field.").chain(httpHelper_->lastError());
95    }
96
97    qDebug() << "Finished login";
98}
99
100void BCAccount::doLogout() {
101    qDebug() << "Starting logout";
102
103    QString requestResult;
104    if (!httpHelper_->get(LOGOUT_PAGE, requestResult)) {
105        qWarning() << tr("Error during logout: ") + httpHelper_->lastError().chainedWhat();
106        qWarning() << tr("But ignoring it, since we clear the cookies and are therefore also logged out");
107    }
108    httpHelper_->cookieManager()->clearCookies();
109
110    qDebug() << "Finished logout";
111}
112
113bool BCAccount::stillLoggedIn() {
114    qDebug() << "Starting still-logged-in-check";
115
116    QString requestResult;
117    bool result = true;
118    if (!httpHelper_->get(MAIN_PAGE, requestResult)) {
119        result = false;
120        qWarning() << tr("Error while checking if we are still logged in: ") + httpHelper_->lastError().chainedWhat();
121        qWarning() << tr("But ignoring it, since we just do a new login attempt.");
122    }
123    result = result &&
124             requestResult.contains("CobYouthSMSSenden:txtMessage", Qt::CaseInsensitive);
125
126    qDebug() << "Ended still-logged-in-check";
127    return result;
128}
129
130
131void BCAccount::_doPost(const QMap<QString, QString>& posts) {
132    QMap<QString, QString> posts_ (posts);
133    posts_.insert("__EVENTTARGET", "");
134    posts_.insert("__EVENTARGUMENT", "");
135    posts_.insert("__VIEWSTATE", "");
136
137    QRegExp rx("<input.*name=\"__VIEWSTATE_SCM\".*value=\"(.*)\".*/>");
138    rx.setMinimal(true);
139    rx.setCaseSensitivity(Qt::CaseInsensitive);
140    if (rx.indexIn(lastHtml_) != -1) {
141        posts_.insert("__VIEWSTATE_SCM", rx.cap(1));
142    }
143
144    if (!httpHelper_->post(MAIN_PAGE, lastHtml_, QMap<QString, QString>(), posts_)) {
145        throw Http::EReadException(tr("Error while doing a post")).addDebugInfos(posts_).chain(httpHelper_->lastError());
146    }
147
148    rx.setPattern("<span.*id=\"CobYouthSMSSenden_lblErrorBox\".*>(.*)</span>");
149    if (rx.indexIn(lastHtml_) != -1) {
150        throw EException(rx.cap(1));
151    }
152}
153
154void BCAccount::_parseMainPage(){
155    QRegExp rx;
156    rx.setMinimal(true);                        // Non-Greedy
157    rx.setCaseSensitivity(Qt::CaseInsensitive); // Caseinsensitive
158
159    qDebug() << "Parsing main page:";
160
161    BCGateway* gtwy = static_cast<BCGateway*>(gateway());
162
163    try {
164        rx.setPattern("<input.*id=\"CobYouthSMSSenden_txtMessageDisabled\".*value=\"(.*)\".*/>");
165        if (rx.indexIn(lastHtml_) == -1) {
166            throw EException(tr("Could not get the addon text!"));
167        }
168        gtwy->setAddonText(rx.cap(1));
169        qDebug() << "  Addon text: " + rx.cap(1);
170
171        rx.setPattern("<input.*id=\"lblcounter\".*value='(\\d*)'.*/?>");
172        if (rx.indexIn(lastHtml_) == -1){
173            throw EException(tr("Could not get the longSMSLength!"));
174        }
175        gtwy->setLongSMSLength(rx.cap(1).toInt() + gtwy->addonText().length());
176        qDebug() << "  Long SMS lenght: " + rx.cap(1);
177
178        rx.setPattern("<span.*id=\"CobYouthMMSSMSKonto_lblGuthaben\">(\\d*)</span>");
179        if (rx.indexIn(lastHtml_) == -1) {
180            throw EException(tr("Could not get the free sms count!"));
181        }
182    } catch (EException e) {
183        throw EException(tr("Error while parsing the sms-page: ") + e.unchainedWhat());
184    }
185    setFreeSMSCount(rx.cap(1).toInt());
186    qDebug() << "  Free SMS count: " + rx.cap(1);
187}
188
189void BCAccount::_removeRecipients() {
190    qDebug() << "Removing recipients";
191
192    QMap<QString, QString> posts;
193    posts.insert("CobYouthSMSSenden:RecipientsDG:_ctl2:_ctl0", "");
194
195    try {
196        while (lastHtml_.contains("CobYouthSMSSenden:RecipientsDG:_ctl2:_ctl0", Qt::CaseInsensitive)){
197            _doPost(posts);
198        }
199    } catch (EException e) {
200        throw EException(tr("Could not remove old recipients: ") + e.unchainedWhat());
201    }
202    qDebug() << "Recipients removed";
203}
204
205void BCAccount::_addRecipient(const IContact* recipient) {
206    qDebug() << "Starting adding recipient " + recipient->number().toString();
207
208    QMap<QString, QString> posts;
209    posts.insert("CobYouthSMSSenden:btnAddReceiver", "");
210    posts.insert("CobYouthSMSSenden:txtNewReceiver", recipient->number().toString("aaau"));
211
212    try {
213        _doPost(posts);
214    } catch (EException e) {
215        throw EException(tr("Could not add a recipient: ") + e.what());
216    }
217    qDebug() << "Recipient added";
218}
219
220void BCAccount::_sendSMS(const QString& text) {
221    qDebug() << "Start of sending part of SMS";
222
223    QString txt = text;
224    txt.replace("&", "%26");
225    txt.replace("+", "%2B");
226
227    QMap<QString, QString> posts;
228    posts.insert("CobYouthSMSSenden:btnSend", "");
229    posts.insert("CobYouthSMSSenden:txtMessage", txt);
230
231    try {
232        _doPost(posts);
233    } catch (EException e) {
234        throw EException(tr("A part of the sms could not be sent to all recipients! ") + e.what());
235    }
236
237    qDebug() << "Part of SMS sent";
238}
239
240
241
242void BCAccount::sendSMS(const QString& message, const QSet<IContact*>& recipients) {
243    if ((message == "") || recipients.empty()){
244        return;
245    }
246
247    qDebug() << "Starting sending SMS";
248   
249    /* PROGRESS:
250     *
251     * Login:    10%
252     *
253     * Send SMS: 80%
254     *   - Remove recipients: 20%
255     *   - Add recipients:    60%
256     *   - Send SMS:          20%
257     *
258     * Logout:   10%
259     *
260     */
261
262    try {
263        setProgress(0);
264
265        uncancelSendingSMS();
266
267        try {
268            setStatus(LoginAccount::Status::Login);
269            login();
270        }catch (...) {
271            // TODO
272            setStatus(LoginAccount::Status::Error);
273        }
274
275        _parseMainPage();
276
277        QList<QString> longSMSLst  = gateway()->splitTextToLongSMS(message);
278        QList<QString> shortSMSLst = gateway()->splitTextToShortSMS(message);
279
280        int freeSMSNeeded = shortSMSLst.size() * recipients.size();
281        if (freeSMSNeeded > freeSMSCount()) {
282            throw EException(tr("You have only %1 SMS for free. (You need at least %2 SMS left to send this message!)").arg(freeSMSCount()).arg(freeSMSNeeded));
283        }
284
285        setProgress(10);
286
287
288        int percent_per_sms = 80 / longSMSLst.size();
289
290        int x = 0;
291        QListIterator<QString> i(longSMSLst);
292        while (i.hasNext()) {
293            int y = 0;
294
295            QSetIterator<IContact*> j(recipients);
296            do {
297                setStatus(LoginAccount::Status::RemovingRecipients);
298                _removeRecipients(); // Remove all recipients
299                setProgress(percent_per_sms * 20/100, IncProgress);
300
301
302                int recipientsNum = std::min(recipients.size(), (y+1)*MAX_MOBILE);
303                setStatus(LoginAccount::Status::AddingRecipients.arg(y*MAX_MOBILE + 1).arg(recipientsNum).arg(recipients.size()));
304
305
306                int percent_per_contact = (percent_per_sms * 60/100) / recipientsNum;
307
308                int ix = 0;
309                while (j.hasNext() && (ix < MAX_MOBILE)) {
310                    _addRecipient(j.next());
311                    setProgress(percent_per_contact, IncProgress);
312
313                    ix++;
314                }
315
316                setStatus(LoginAccount::Status::SendingSMS.arg(x+1).arg(longSMSLst.size()));
317                _sendSMS(i.next());
318                setStatus(LoginAccount::Status::SMSSent, percent_per_sms * 20/100, IncProgress);
319
320                y++;
321            } while ((y * MAX_MOBILE) < recipients.size()); // Repeat this step until the sms is sent to all recipients (if there are more than allowed to be addressed at once)
322
323            x++;
324        }
325
326        _parseMainPage();
327        setStatus(LoginAccount::Status::Logout, 90);
328        logout();
329
330        // TODO: check if sending was cancelled -> set status to "user abort"
331        setStatus(LoginAccount::Status::SMSSent, 100);
332
333    }catch (EException e) {
334        // TODO
335        qDebug() << "An error occured: " + e.what();
336        setStatus(LoginAccount::Status::Error);
337    }
338   
339    qDebug() << "SMS has been sent";
340}
341
342}
Note: See TracBrowser for help on using the repository browser.