File indexing completed on 2024-06-23 04:03:41
0001 /* 0002 * Copyright (C) 2003 Justin Karneges 0003 * 0004 * This library is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU Lesser General Public 0006 * License as published by the Free Software Foundation; either 0007 * either version 2 0008 of the License, or (at your option) any later version.1 of the License, or (at your option) any later version. 0009 * 0010 * This library is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 * Lesser General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU Lesser General Public 0016 * License along with this library; if not, write to the Free Software 0017 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0018 * 0019 */ 0020 0021 #include <QTimer> 0022 0023 #include "safedelete.h" 0024 #include "xmpp_task.h" 0025 #include "xmpp_client.h" 0026 #include "xmpp_xmlcommon.h" 0027 0028 using namespace XMPP; 0029 0030 class Task::TaskPrivate 0031 { 0032 public: 0033 TaskPrivate() {} 0034 0035 QString id; 0036 bool success; 0037 int statusCode; 0038 QString statusString; 0039 Client *client; 0040 bool insig, deleteme, autoDelete; 0041 bool done; 0042 }; 0043 0044 Task::Task(Task *parent) 0045 :QObject(parent) 0046 { 0047 init(); 0048 0049 d->client = parent->client(); 0050 d->id = client()->genUniqueId(); 0051 connect(d->client, &Client::disconnected, this, &Task::clientDisconnected); 0052 } 0053 0054 Task::Task(Client *parent, bool) 0055 :QObject(0) 0056 { 0057 init(); 0058 0059 d->client = parent; 0060 connect(d->client, &Client::disconnected, this, &Task::clientDisconnected); 0061 } 0062 0063 Task::~Task() 0064 { 0065 delete d; 0066 } 0067 0068 void Task::init() 0069 { 0070 d = new TaskPrivate; 0071 d->success = false; 0072 d->insig = false; 0073 d->deleteme = false; 0074 d->autoDelete = false; 0075 d->done = false; 0076 } 0077 0078 Task *Task::parent() const 0079 { 0080 return (Task *)QObject::parent(); 0081 } 0082 0083 Client *Task::client() const 0084 { 0085 return d->client; 0086 } 0087 0088 QDomDocument *Task::doc() const 0089 { 0090 return client()->doc(); 0091 } 0092 0093 QString Task::id() const 0094 { 0095 return d->id; 0096 } 0097 0098 bool Task::success() const 0099 { 0100 return d->success; 0101 } 0102 0103 int Task::statusCode() const 0104 { 0105 return d->statusCode; 0106 } 0107 0108 const QString & Task::statusString() const 0109 { 0110 return d->statusString; 0111 } 0112 0113 void Task::go(bool autoDelete) 0114 { 0115 d->autoDelete = autoDelete; 0116 0117 if (!client() || !&client()->stream()) { 0118 qWarning("Task::go(): attempted to send a task over the broken connection."); 0119 if (autoDelete) { 0120 deleteLater(); 0121 } 0122 } 0123 else { 0124 onGo(); 0125 } 0126 } 0127 0128 bool Task::take(const QDomElement &x) 0129 { 0130 const QObjectList p = children(); 0131 0132 // pass along the xml 0133 Task *t; 0134 for(QObjectList::ConstIterator it = p.begin(); it != p.end(); ++it) { 0135 QObject *obj = *it; 0136 if(!obj->inherits("XMPP::Task")) 0137 continue; 0138 0139 t = static_cast<Task*>(obj); 0140 if(t->take(x)) 0141 return true; 0142 } 0143 0144 return false; 0145 } 0146 0147 void Task::safeDelete() 0148 { 0149 if(d->deleteme) 0150 return; 0151 0152 d->deleteme = true; 0153 if(!d->insig) 0154 SafeDelete::deleteSingle(this); 0155 } 0156 0157 void Task::onGo() 0158 { 0159 } 0160 0161 void Task::onDisconnect() 0162 { 0163 if(!d->done) { 0164 d->success = false; 0165 d->statusCode = ErrDisc; 0166 d->statusString = tr("Disconnected"); 0167 0168 // delay this so that tasks that react don't block the shutdown 0169 QTimer::singleShot(0, this, &Task::done); 0170 } 0171 } 0172 0173 void Task::send(const QDomElement &x) 0174 { 0175 client()->send(x); 0176 } 0177 0178 void Task::setSuccess(int code, const QString &str) 0179 { 0180 if(!d->done) { 0181 d->success = true; 0182 d->statusCode = code; 0183 d->statusString = str; 0184 done(); 0185 } 0186 } 0187 0188 void Task::setError(const QDomElement &e) 0189 { 0190 if(!d->done) { 0191 d->success = false; 0192 getErrorFromElement(e, d->client->streamBaseNS(), &d->statusCode, &d->statusString); 0193 done(); 0194 } 0195 } 0196 0197 void Task::setError(int code, const QString &str) 0198 { 0199 if(!d->done) { 0200 d->success = false; 0201 d->statusCode = code; 0202 d->statusString = str; 0203 done(); 0204 } 0205 } 0206 0207 void Task::done() 0208 { 0209 if(d->done || d->insig) 0210 return; 0211 d->done = true; 0212 0213 if(d->deleteme || d->autoDelete) 0214 d->deleteme = true; 0215 0216 d->insig = true; 0217 finished(); 0218 d->insig = false; 0219 0220 if(d->deleteme) 0221 SafeDelete::deleteSingle(this); 0222 } 0223 0224 void Task::clientDisconnected() 0225 { 0226 onDisconnect(); 0227 } 0228 0229 void Task::debug(const char *fmt, ...) 0230 { 0231 va_list ap; 0232 va_start(ap, fmt); 0233 const QString str = QString::vasprintf(fmt, ap); 0234 va_end(ap); 0235 debug(str); 0236 } 0237 0238 void Task::debug(const QString &str) 0239 { 0240 client()->debug(QString("%1: ").arg(metaObject()->className()) + str); 0241 } 0242 0243 0244 /** 0245 * \brief verifiys a stanza is a IQ reply for this task 0246 * 0247 * it checks that the stanze is form the jid the request was send to and the id and the namespace (if given) match. 0248 * 0249 * it further checks that the sender jid is not empty (except if \a to is our server), it's not from 0250 * our bare jid (except if send to one of our resources or our server) 0251 * \param x the stanza to test 0252 * \param to the Jid this task send a IQ to 0253 * \param id the id of the send IQ 0254 * \param xmlns the expected namespace if the reply (if non empty) 0255 * \return true if it's a valid reply 0256 */ 0257 0258 bool Task::iqVerify(const QDomElement &x, const Jid &to, const QString &id, const QString &xmlns) 0259 { 0260 if(x.tagName() != "iq") 0261 return false; 0262 0263 Jid from(x.attribute("from")); 0264 Jid local = client()->jid(); 0265 Jid server = client()->host(); 0266 0267 // empty 'from' ? 0268 if(from.isEmpty()) { 0269 // allowed if we are querying the server 0270 if(!to.isEmpty() && !to.compare(server)) 0271 return false; 0272 } 0273 // from ourself? 0274 else if(from.compare(local, false) || from.compare(local.domain(),false)) { 0275 // allowed if we are querying ourself or the server 0276 if(!to.isEmpty() && !to.compare(local, false) && !to.compare(server)) 0277 return false; 0278 } 0279 // from anywhere else? 0280 else { 0281 if(!from.compare(to)) 0282 return false; 0283 } 0284 0285 if(!id.isEmpty()) { 0286 if(x.attribute("id") != id) 0287 return false; 0288 } 0289 0290 if(!xmlns.isEmpty()) { 0291 if(queryNS(x) != xmlns) 0292 return false; 0293 } 0294 0295 return true; 0296 } 0297