source: SMSSender/gateways/SwisscomXtraZone/src/business/BCAccount.cpp @ 71:415b45c71663

3.0
Last change on this file since 71:415b45c71663 was 71:415b45c71663, checked in by Sämy Zehnder <saemy.zehnder@…>, 12 years ago
  • Reorganized all the libraries. libinterfaces and libgateways are removed now and libdatatypes contains now all these files.
File size: 8.6 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    lastHtml_   = httpHelper_->post(LOGIN_PAGE, QMap<QString, QString>(), posts);
86
87    if (lastHtml_.contains("Begin error region content", Qt::CaseInsensitive)) {
88        throw LoginAccount::ELoginException(LoginAccount::ELoginException::InvalidLoginData);
89    }
90
91    if (!lastHtml_.contains("CobYouthSMSSenden:txtMessage", Qt::CaseInsensitive)) {
92        throw LoginAccount::ELoginException(LoginAccount::ELoginException::Unknown, "The returned page contains no message field.");
93    }
94
95    qDebug() << "Finished login";
96}
97
98void BCAccount::doLogout() {
99    qDebug() << "Starting logout";
100
101    httpHelper_->get(LOGOUT_PAGE);
102    httpHelper_->cookieManager()->clearCookies();
103
104    qDebug() << "Finished logout";
105}
106
107bool BCAccount::stillLoggedIn() {
108    qDebug() << "Starting still-logged-in-check";
109
110    bool result = httpHelper_->get(MAIN_PAGE).contains("CobYouthSMSSenden:txtMessage", Qt::CaseInsensitive);
111
112    qDebug() << "Ended still-logged-in-check";
113    return result;
114}
115
116
117void BCAccount::_doPost(const QMap<QString, QString>& posts) {
118    QMap<QString, QString> posts_ (posts);
119    posts_.insert("__EVENTTARGET", "");
120    posts_.insert("__EVENTARGUMENT", "");
121    posts_.insert("__VIEWSTATE", "");
122
123    QRegExp rx("<input.*name=\"__VIEWSTATE_SCM\".*value=\"(.*)\".*/>");
124    rx.setMinimal(true);
125    rx.setCaseSensitivity(Qt::CaseInsensitive);
126    if (rx.indexIn(lastHtml_) != -1) {
127        posts_.insert("__VIEWSTATE_SCM", rx.cap(1));
128    }
129
130    lastHtml_ = httpHelper_->post(MAIN_PAGE, QMap<QString, QString>(), posts_);
131
132    rx.setPattern("<span.*id=\"CobYouthSMSSenden_lblErrorBox\".*>(.*)</span>");
133    if (rx.indexIn(lastHtml_) != -1) {
134        throw EException(rx.cap(1));
135    }
136}
137
138void BCAccount::_parseMainPage(){
139    QRegExp rx;
140    rx.setMinimal(true);                        // Non-Greedy
141    rx.setCaseSensitivity(Qt::CaseInsensitive); // Caseinsensitive
142
143    qDebug() << "Parsing main page:";
144
145    BCGateway* gtwy = static_cast<BCGateway*>(gateway());
146
147    rx.setPattern("<input.*id=\"CobYouthSMSSenden_txtMessageDisabled\".*value=\"(.*)\".*/>");
148    if (rx.indexIn(lastHtml_) == -1) {
149        throw EException(tr("Could not get the addon text!"));
150    }
151    gtwy->setAddonText(rx.cap(1));
152    qDebug() << "  Addon text: " + rx.cap(1);
153
154    rx.setPattern("<input.*id=\"lblcounter\".*value='(\\d*)'.*/?>");
155    if (rx.indexIn(lastHtml_) == -1){
156        throw EException(tr("Could not get the longSMSLength!"));
157    }
158    gtwy->setLongSMSLength(rx.cap(1).toInt() + gtwy->addonText().length());
159    qDebug() << "  Long SMS lenght: " + rx.cap(1);
160
161    rx.setPattern("<span.*id=\"CobYouthMMSSMSKonto_lblGuthaben\">(\\d*)</span>");
162    if (rx.indexIn(lastHtml_) == -1) {
163        throw EException(tr("Could not get the free sms count!"));
164    }
165    setFreeSMSCount(rx.cap(1).toInt());
166    qDebug() << "  Free SMS count: " + rx.cap(1);
167}
168
169void BCAccount::_removeRecipients() {
170    qDebug() << "Removing recipients";
171
172    QMap<QString, QString> posts;
173    posts.insert("CobYouthSMSSenden:RecipientsDG:_ctl2:_ctl0", "");
174
175    while (lastHtml_.contains("CobYouthSMSSenden:RecipientsDG:_ctl2:_ctl0", Qt::CaseInsensitive)){
176        _doPost(posts);
177    }
178    qDebug() << "Recipients removed";
179}
180
181void BCAccount::_addRecipient(const IContact* recipient) {
182    qDebug() << "Starting adding recipient " + recipient->number().toString();
183
184    QMap<QString, QString> posts;
185    posts.insert("CobYouthSMSSenden:btnAddReceiver", "");
186    posts.insert("CobYouthSMSSenden:txtNewReceiver", recipient->number().toString("aaau"));
187
188    _doPost(posts);
189    qDebug() << "Recipient added";
190}
191
192void BCAccount::_sendSMS(const QString& text) {
193    qDebug() << "Starting sending part of SMS";
194
195    QString txt = text;
196    txt.replace("&", "%26");
197    txt.replace("+", "%2B");
198
199    QMap<QString, QString> posts;
200    posts.insert("CobYouthSMSSenden:btnSend", "");
201    posts.insert("CobYouthSMSSenden:txtMessage", txt);
202
203    _doPost(posts);
204
205    qDebug() << "Part of SMS sent";
206}
207
208
209
210void BCAccount::sendSMS(const QString& message, const QSet<IContact*>& recipients) {
211    if ((message == "") || recipients.empty()){
212        return;
213    }
214
215    qDebug() << "Starting sending SMS";
216   
217    /* PROGRESS:
218     *
219     * Login:    10%
220     *
221     * Send SMS: 80%
222     *   - Remove recipients: 20%
223     *   - Add recipients:    60%
224     *   - Send SMS:          20%
225     *
226     * Logout:   10%
227     *
228     */
229
230    try {
231        setProgress(0);
232
233    uncancelSendingSMS();
234
235    try {
236        setStatus(LoginAccount::Status::Login);
237        login();
238    }catch (...) {
239        // TODO
240        setStatus(LoginAccount::Status::Error);
241    }
242
243    _parseMainPage();
244
245    QList<QString> longSMSLst  = gateway()->splitTextToLongSMS(message);
246    QList<QString> shortSMSLst = gateway()->splitTextToShortSMS(message);
247
248    int freeSMSNeeded = shortSMSLst.size() * recipients.size();
249    if (freeSMSNeeded > freeSMSCount()) {
250        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));
251    }
252
253    setProgress(10);
254
255
256    int percent_per_sms = 80 / longSMSLst.size();
257
258    int x = 0;
259    QListIterator<QString> i(longSMSLst);
260    while (i.hasNext()) {
261        int y = 0;
262
263        QSetIterator<IContact*> j(recipients);
264        do {
265            setStatus(LoginAccount::Status::RemovingRecipients);
266            _removeRecipients(); // Remove all recipients
267            setProgress(percent_per_sms * 20/100, IncProgress);
268
269
270            int recipientsNum = std::min(recipients.size(), (y+1)*MAX_MOBILE);
271            setStatus(LoginAccount::Status::AddingRecipients.arg(y*MAX_MOBILE + 1).arg(recipientsNum).arg(recipients.size()));
272
273
274            int percent_per_contact = (percent_per_sms * 60/100) / recipientsNum;
275
276            int ix = 0;
277            while (j.hasNext() && (ix < MAX_MOBILE)) {
278                _addRecipient(j.next());
279                setProgress(percent_per_contact, IncProgress);
280
281                ix++;
282            }
283
284            setStatus(LoginAccount::Status::SendingSMS.arg(x+1).arg(longSMSLst.size()));
285            _sendSMS(i.next());
286            setStatus(LoginAccount::Status::SMSSent, percent_per_sms * 20/100, IncProgress);
287
288            y++;
289        } 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)
290
291        x++;
292    }
293
294    _parseMainPage();
295    setStatus(LoginAccount::Status::Logout, 90);
296    logout();
297
298    // TODO: check if sending was cancelled -> set status to "user abort"
299    setStatus(LoginAccount::Status::SMSSent, 100);
300
301    }catch (EException e) {
302        // TODO
303        qDebug() << "An error occured: " + QString::fromLatin1(e.what());
304        setStatus(LoginAccount::Status::Error);
305    }
306   
307    qDebug() << "SMS has been sent";
308}
309
310}
Note: See TracBrowser for help on using the repository browser.