1 /* This file is part of the KDE project
2 Copyright (C) 2005 Michal Vaner <michal.vaner@kdemail.net>
3 Copyright (C) 2008-2009 Pali Rohár <pali.rohar@gmail.com>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License version 2 as published by the Free Software Foundation.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18
19 */
20 #include "skype.h"
21 #include "skypeconnection.h"
22 #include "skypeaccount.h"
23
24 #include <kdebug.h>
25 #include <qstring.h>
26 #include <klocale.h>
27 #include <kmessagebox.h>
28 #include <knotification.h>
29 #include <qtimer.h>
30 #include <QDateTime>
31
32 #define PROTOCOL_MAX 8
33 #define PROTOCOL_MIN 6
34 #define TEST_QUIT if (!d->connection.connected()) return;
35
36 ///This one indicates, weather the Skype is connected (does not mean weather it is marked as online, just if it has connection to the site)
37 typedef enum {
38 csOffline,
39 csConnecting,
40 csPausing,
41 csOnline,
42 csLoggedOut
43 } connectionStatus;
44
45 ///This describes what the user is marked as. If online here and not connected to skype site, he is probably offline
46 typedef enum {
47 usUnknown,
48 usOffline,
49 usOnline,
50 usSkypeMe,
51 usAway,
52 usNA,
53 usDND,
54 usInvisible
55 } userStatus;
56
57 class SkypePrivate {
58 public:
59 ///The connection
60 SkypeConnection connection;
61 ///The queue
62 QStringList messageQueue;
63 ///How do we start skype?
64 int launchType;
65 ///What is our name?
66 QString appName;
67 ///Should the skypeconnection start skype automatically if it is not running?
68 bool start;
69 ///Is the skype connected?
70 connectionStatus connStatus;
71 ///What is the online status for the user?
72 userStatus onlineStatus;
73 ///This contains last search request to know, what we were searching for
74 QString searchFor;
75 ///Is the hitch-mode enabled?
76 bool hitch;
77 ///Is the mark read messages mode enabled?
78 bool mark;
79 ///The skype account this connection belongs to
80 SkypeAccount &account;
81 ///Should we show the message that Skype died? It if off when going offline, this removes that onnoying message when logging off and skype finishes first.
82 bool showDeadMessage;
83 ///Do we automatically scan for unread messages on login?
84 bool scanForUnread;
85 ///Constructor
SkypePrivate(SkypeAccount & _account)86 SkypePrivate(SkypeAccount &_account) : account(_account) {};//initialize all that needs it
87 ///List of known calls, so they are not showed twice
88 QStringList knownCalls;
89 ///Are the pings enabled?
90 bool pings;
91 ///Pinging timer
92 QTimer *pingTimer;
93 ///What bus is used now?
94 int bus;
95 ///The launch timeout (after that no connection -> unsuccessful -> error)
96 int launchTimeout;
97 ///By what command is skype started?
98 QString skypeCommand;
99 ///Do we wait before connecting?
100 int waitBeforeConnect;
101 ///List of alredy received messages (IDs)
102 QStringList recvMessages;
103 ///Skype Groups with contacts <id, contact>
104 QMultiHash <int, QString> groupsContacts;
105 ///Skype Groups names <name, id>
106 QMultiHash <QString, int> groupsNames;
107 ///Timer to fix & load groups
108 QTimer *fixGroupTimer;
109 };
110
Skype(SkypeAccount & account)111 Skype::Skype(SkypeAccount &account) : QObject() {
112 kDebug(SKYPE_DEBUG_GLOBAL);
113
114 d = new SkypePrivate(account);//create the d-pointer
115
116 //initial values
117 d->connStatus = csOffline;
118 d->onlineStatus = usOffline;
119 d->searchFor = "";
120 d->pings = false;
121 d->pingTimer = new QTimer;
122 d->fixGroupTimer = new QTimer;
123
124 connect(&d->connection, SIGNAL(connectionClosed(int)), this, SLOT(closed(int)));//tell me if you close/lose the connection
125 connect(&d->connection, SIGNAL(connectionDone(int,int)), this, SLOT(connectionDone(int,int)));//Do something whe he finishes connecting
126 connect(&d->connection, SIGNAL(error(QString)), this, SLOT(error(QString)));//Listen for errors
127 connect(&d->connection, SIGNAL(received(QString)), this, SLOT(skypeMessage(QString)));//Take all incoming messages
128 connect(d->pingTimer, SIGNAL(timeout()), this, SLOT(ping()));
129 connect(d->fixGroupTimer, SIGNAL(timeout()), this, SLOT(fixGroups()));//fix & load groups to memory
130 }
131
~Skype()132 Skype::~Skype() {
133 kDebug(SKYPE_DEBUG_GLOBAL);
134
135 if (d->connection.connected())
136 d->connection << QString("SET USERSTATUS OFFLINE");
137
138 d->pingTimer->stop();
139 d->pingTimer->deleteLater();
140
141 delete d;//release the memory
142 }
143
setOnline()144 void Skype::setOnline() {
145 kDebug(SKYPE_DEBUG_GLOBAL);
146 d->showDeadMessage = true;
147
148 if ((d->onlineStatus == usOnline) && (d->connStatus == csOnline) && (d->connection.connected()))
149 return;//Already online
150
151 queueSkypeMessage("SET USERSTATUS ONLINE", true);//just send the message
152 }
153
setUserProfileRichMoodText(const QString & message)154 void Skype::setUserProfileRichMoodText(const QString &message) {
155 kDebug(SKYPE_DEBUG_GLOBAL);
156
157 if (! d->connection.connected())
158 return;
159
160 queueSkypeMessage(QString("SET PROFILE RICH_MOOD_TEXT %1").arg(message), false);
161 }
162
setOffline()163 void Skype::setOffline() {
164 kDebug(SKYPE_DEBUG_GLOBAL);
165 d->showDeadMessage = false;
166
167 d->connection << QString("SET USERSTATUS OFFLINE");//this one special, do not connect to skype because of that
168 d->connection % QString("SET SILENT_MODE OFF");//try turn on (to default) all gui skype notification - this is not supported by skype yet, once it will works
169 d->connection.disconnectSkype();
170 }
171
setAway()172 void Skype::setAway() {
173 kDebug(SKYPE_DEBUG_GLOBAL);
174 d->showDeadMessage = true;
175
176 queueSkypeMessage("SET USERSTATUS AWAY", true);
177 }
178
setNotAvailable()179 void Skype::setNotAvailable() {
180 kDebug(SKYPE_DEBUG_GLOBAL);
181 d->showDeadMessage = true;
182
183 queueSkypeMessage("SET USERSTATUS NA", true);
184 }
185
setDND()186 void Skype::setDND() {
187 kDebug(SKYPE_DEBUG_GLOBAL);
188 d->showDeadMessage = true;
189
190 queueSkypeMessage("SET USERSTATUS DND", true);
191 }
192
setInvisible()193 void Skype::setInvisible() {
194 kDebug(SKYPE_DEBUG_GLOBAL);
195 d->showDeadMessage = true;
196
197 queueSkypeMessage("SET USERSTATUS INVISIBLE", true);
198 }
199
setSkypeMe()200 void Skype::setSkypeMe() {
201 kDebug(SKYPE_DEBUG_GLOBAL);
202 d->showDeadMessage = true;
203
204 queueSkypeMessage("SET USERSTATUS SKYPEME", true);
205 }
206
queueSkypeMessage(const QString & message,bool deleteQueue)207 void Skype::queueSkypeMessage(const QString &message, bool deleteQueue) {
208 kDebug(SKYPE_DEBUG_GLOBAL);
209
210 if (d->connection.connected()) {//we are connected, so just send it
211 d->connection << message;//just send it
212 } else {
213 emit statusConnecting();//Started connecting to skype
214 if (deleteQueue)
215 d->messageQueue.clear();//delete all old messages
216 d->messageQueue << message;//add the new one
217 d->connection.connectSkype((d->start) ? d->skypeCommand : "", d->appName, PROTOCOL_MAX, d->bus, d->launchTimeout, d->waitBeforeConnect);//try to connect
218 }
219 }
220
setValues(int launchType,const QString & appName)221 void Skype::setValues(int launchType, const QString &appName) {
222 kDebug(SKYPE_DEBUG_GLOBAL);
223
224 d->appName = appName;
225 if (d->appName.isEmpty()) //The defaut one?
226 d->appName = "Kopete";
227 d->launchType = launchType;
228 switch (launchType) {
229 case 0: //start the skype if it is needed
230 d->start = true;//just set autostart
231 break;
232 case 1: //do not start
233 d->start = false;//do not start
234 break;
235 }
236 }
237
closed(int)238 void Skype::closed(int) {
239 kDebug(SKYPE_DEBUG_GLOBAL);
240
241 emit wentOffline();//No longer connected
242 d->messageQueue.clear();//no messages will wait, it was lost
243 d->pingTimer->stop();
244 d->fixGroupTimer->stop();
245 }
246
connectionDone(int error,int protocolVer)247 void Skype::connectionDone(int error, int protocolVer) {
248 kDebug(SKYPE_DEBUG_GLOBAL);
249
250 if (d->pings) {
251 d->pingTimer->start(1000);
252 }
253
254 if (error == seSuccess) {//It worked
255 if (protocolVer < PROTOCOL_MIN) {//The protocol is too old, it is not useable
256 this->error(i18n("This version of Skype is too old, consider upgrading"));
257 connectionDone(seUnknown, 0);//So act like there was an error
258 return;//and it is all fo now
259 }
260
261 d->connection % QString("MINIMIZE");//try hide Skype to system tray
262 d->connection % QString("SET SILENT_MODE ON");//try turn off all gui skype notification - this is not supported by skype yet, once it will works
263 ///TODO: Set silent mode on, when is turned off
264
265 while (d->messageQueue.size()) {//It isn't empty yet?
266 QStringList::iterator it = d->messageQueue.begin();//take the first one
267 d->connection << (*it);//send the message
268 //d->messageQueue.remove(it);//remove this one
269 d->messageQueue.removeFirst();
270 }
271 emit updateAllContacts();//let all contacts update their information
272 fixGroups();//fix & load groups immediately
273 search("FRIENDS");//search for friends - to add them all
274 TEST_QUIT;//if it failed, do not continue
275 d->connection.send("GET USERSTATUS");
276 TEST_QUIT;
277 d->connection.send("GET CONNSTATUS");
278 d->fixGroupTimer->start(60000);//fix & load groups to memory every minutes
279 } else {
280 closed(crLost);//OK, this is wrong, just close the connection/attempt and delete the queue
281 }
282 }
283
error(const QString & message)284 void Skype::error(const QString &message) {
285 kDebug(SKYPE_DEBUG_GLOBAL);
286
287 disconnect(&d->connection, SIGNAL(error(QString)), this, SLOT(error(QString)));//One arror at a time is enough, stop flooding the user
288
289 if (d->showDeadMessage && !d->account.isBusy())//just skip the error message if we are going offline, none ever cares.
290 KNotification::event(KNotification::Error, i18n("Skype protocol"), message);//Show the message
291
292 connect(&d->connection, SIGNAL(error(QString)), this, SLOT(error(QString)));//Continue showing more errors in future
293 }
294
skypeMessage(const QString & message)295 void Skype::skypeMessage(const QString &message) {
296 kDebug(SKYPE_DEBUG_GLOBAL);
297
298 QString messageType = message.section(' ', 0, 0).trimmed().toUpper();//get the first part of the message
299 if (messageType == "CONNSTATUS") {//the connection status
300 QString value = message.section(' ', 1, 1).trimmed().toUpper();//get the second part of the message
301 if (value == "OFFLINE")
302 d->connStatus = csOffline;
303 else if (value == "CONNECTING")
304 d->connStatus = csConnecting;
305 else if (value == "PAUSING")
306 d->connStatus = csPausing;
307 else if (value == "ONLINE")
308 d->connStatus = csOnline;
309 else if (value == "LOGGEDOUT")
310 d->connStatus = csLoggedOut;
311
312 resetStatus();//set new status
313 } else if (messageType == "USERSTATUS") {//Status of this user
314 QString value = message.section(' ', 1, 1).trimmed().toUpper();//get the second part
315 if (value == "UNKNOWN")
316 d->onlineStatus = usUnknown;
317 else if (value == "OFFLINE")
318 d->onlineStatus = usOffline;
319 else if (value == "ONLINE")
320 d->onlineStatus = usOnline;
321 else if (value == "SKYPEME")
322 d->onlineStatus = usSkypeMe;
323 else if (value == "AWAY")
324 d->onlineStatus = usAway;
325 else if (value == "NA")
326 d->onlineStatus = usNA;
327 else if (value == "DND")
328 d->onlineStatus = usDND;
329 else if (value == "INVISIBLE")
330 d->onlineStatus = usInvisible;
331
332 resetStatus();
333 } else if (messageType == "USERS") {//some user info
334 QString theRest = message.section(' ', 1).trimmed();//take the rest
335 if (d->searchFor == "FRIENDS") {//it was initial search for al users
336 QStringList names = theRest.split(", ");//divide it into names by comas
337 kDebug(SKYPE_DEBUG_GLOBAL) << "Names: " << names;//write what you have done with that
338 for (QStringList::iterator it = names.begin(); it != names.end(); ++it) {//run trough the names
339 QString name = (*it).trimmed();//get the name only
340 if (name.isEmpty())
341 continue;//just skip the empty names
342 int groupID = getContactGroupID(name);
343 if ( groupID != -1 )
344 kDebug(SKYPE_DEBUG_GLOBAL) << "Found group for user" << name << groupID << ":" << getGroupName(groupID);
345 else
346 kDebug(SKYPE_DEBUG_GLOBAL) << "Not found group for user" << name;
347 emit newUser(name, groupID);//add the user to list
348 }
349 if (d->scanForUnread)
350 search("MISSEDMESSAGES");
351 }
352 } else if (messageType == "USER") {//This is for some contact
353 const QString &contactId = message.section(' ', 1, 1);//take the second part, it is the user name
354 const QString &type = message.section(' ', 2, 2).trimmed().toUpper();//get what it is
355 if ((type == "FULLNAME") || (type == "DISPLAYNAME") || (type == "SEX") ||
356 (type == "PHONE_HOME") || (type == "PHONE_OFFICE") ||
357 (type == "PHONE_MOBILE") ||
358 (type == "ONLINESTATUS") || (type == "BUDDYSTATUS") || (type == "HOMEPAGE")) {
359 const QString &info = message.section(' ', 2);//and the rest is just the message for that contact
360 emit contactInfo(contactId, info);//and let the contact know
361 } else if ( type == "ISBLOCKED" || type == "ISAUTHORIZED" ) {
362 /// TODO: Implement status ISBLOCKED and ISAUTHORIZED
363 kDebug(SKYPE_DEBUG_GLOBAL) << "Status ISBLOCKED and ISAUTHORIZED is not implemented for contact, ignored";
364 } else if ( type == "ABOUT" ) {
365 /// TODO: Implement info ABOUT
366 kDebug(SKYPE_DEBUG_GLOBAL) << "Info ABOUT is not implemented for contact, ignored";
367 } else if ( type == "RECEIVEDAUTHREQUEST") {
368 if ( getAuthor(contactId) != Skype::Author ) {// Skype send all authorize request min 2x, filter if contact is authorized
369 const QString &info = message.section(' ', 3);
370 emit receivedAuth(contactId, info);
371 kDebug(SKYPE_DEBUG_GLOBAL) << "Received auth request from" << contactId;
372 }
373 } else {
374 kDebug(SKYPE_DEBUG_GLOBAL) << "Unknown message for contact, ignored";
375 }
376 } else if (messageType == "CHATMESSAGE") {//something with message, maebe incoming/sent
377 QString messageId = message.section(' ', 1, 1).trimmed();//get the second part of message - it is the message ID
378 QString type = message.section(' ', 2, 2).trimmed().toUpper();//This part significates what about the message are we talking about (status, body, etc..)
379 QString chatMessageType = (d->connection % QString("GET CHATMESSAGE %1 TYPE").arg(messageId)).section(' ', 3, 3).trimmed().toUpper();
380 if (chatMessageType == "ADDEDMEMBERS") {
381 QString status = message.section(' ', 3, 3).trimmed().toUpper();
382 if (d->recvMessages.contains(messageId))
383 return;
384 d->recvMessages << messageId;
385 const QString &users = (d->connection % QString("GET CHATMESSAGE %1 USERS").arg(messageId)).section(' ', 3).trimmed();
386 QStringList splitUsers = users.split(' ');
387 const QString &chatId = (d->connection % QString("GET CHATMESSAGE %1 CHATNAME").arg(messageId)).section(' ', 3, 3).trimmed();
388 for (QStringList::iterator it = splitUsers.begin(); it != splitUsers.end(); ++it) {
389 if ((*it).toUpper() == getMyself().toUpper())
390 continue;
391 emit joinUser(chatId, *it);
392 }
393 return;
394 } else if (chatMessageType == "LEFT") {
395 QString status = message.section(' ', 3, 3).trimmed().toUpper();
396 if (d->recvMessages.contains(messageId))
397 return;
398 d->recvMessages << messageId;
399 const QString &chatId = (d->connection % QString("GET CHATMESSAGE %1 CHATNAME").arg(messageId)).section(' ', 3, 3).trimmed();
400 const QString &chatType = (d->connection % QString("GET CHAT %1 STATUS").arg(chatId)).section(' ', 3, 3).trimmed().toUpper();
401 if ((chatType == "DIALOG") || (chatType == "LEGACY_DIALOG"))
402 return;
403 const QString &user = (d->connection % QString("GET CHATMESSAGE %1 FROM_HANDLE").arg(messageId)).section(' ', 3, 3).trimmed();
404 const QString &reason = (d->connection % QString("GET CHATMESSAGE %1 LEAVEREASON").arg(messageId)).section(' ', 3, 3).trimmed().toUpper();
405 QString showReason = i18n("Unknown");
406 if (reason == "USER_NOT_FOUND") {
407 showReason = i18n("User not found");
408 } else if (reason == "USER_INCAPABLE") {
409 showReason = i18n("Does not have multi-user chat capability");
410 } else if ((reason == "ADDER_MUST_BE_FRIEND") || ("ADDER_MUST_BE_AUTHORIZED")) {
411 showReason = i18n("Chat denied");
412 } else if (reason == "UNSUBSCRIBE") {
413 showReason = "";
414 }
415 if (user.toUpper() == getMyself().toUpper())
416 return;
417 emit leftUser(chatId, user, showReason);
418 return;
419 }
420 if (type == "STATUS") {//OK, status of some message has changed, check what is it
421 QString value = message.section(' ', 3, 3).trimmed().toUpper();//get the last part, what status it is
422 if (value == "RECEIVED") {//OK, received new message, possibly read it
423 if (chatMessageType == "SAID") {//OK, it is some IM
424 hitchHike(messageId);//receive the message
425 }
426 } else if (value == "SENDING") {
427 if ((d->connection % QString("GET CHATMESSAGE %1 TYPE").arg(messageId)).section(' ', 3, 3).trimmed().toUpper() == "SAID") {
428 emit gotMessageId(messageId);
429 }
430 } else if (value == "SENT") {//Sending out some message, that means it is a new one
431 if ((d->connection % QString("GET CHATMESSAGE %1 TYPE").arg(messageId)).section(' ', 3, 3).trimmed().toUpper() == "SAID")//it is some message I'm interested in
432 emit gotMessageId(messageId);//Someone may be interested in its ID
433 if (d->recvMessages.contains(messageId))
434 return;//we already got this one
435 d->recvMessages << messageId;
436 const QString &chat = (d->connection % QString("GET CHATMESSAGE %1 CHATNAME").arg(messageId)).section(' ', 3, 3).trimmed();
437 const QString &body = (d->connection % QString("GET CHATMESSAGE %1 BODY").arg(messageId)).section(' ', 3);
438 if (!body.isEmpty())//sometimes skype shows empty messages, just ignore them
439 emit outgoingMessage(messageId, body, chat);
440 }
441 } else if ( type == "EDITED_TIMESTAMP" ) {//timestamp of message was edited
442 ///TODO: Implement this
443 kDebug(SKYPE_DEBUG_GLOBAL) << "Timestamp of message" << messageId << "was edited, this is not implemented now";
444 } else if ( type == "EDITED_BY" ) {//this message was edited
445 ///TODO: Implement this
446 QString editedBy = message.section(' ', 3, 3).trimmed();
447 kDebug(SKYPE_DEBUG_GLOBAL) << "Message" << messageId << "was edited by" << editedBy << ", this is not implemented now";
448 } else if ( type == "BODY" ) { //This message was edited and has new body
449 ///TODO: Implement this
450 QString newBody = message.section(' ', 3, 3).trimmed();
451 kDebug(SKYPE_DEBUG_GLOBAL) << "Message" << messageId << "was edited to" << newBody << ", this is not implemented now";
452 }
453 } else if (messageType == "CHATMESSAGES") {
454 if (d->searchFor == "MISSEDMESSAGES") {//Theese are messages we did not read yet
455 QStringList messages = message.section(' ', 1).split(',');//get the meassage IDs
456 for (QStringList::iterator it = messages.begin(); it != messages.end(); ++it) {
457 QString Id = (*it).trimmed();
458 if (Id.isEmpty())
459 continue;
460 if ( (d->connection % QString("GET CHATMESSAGE %1 FROM_HANDLE").arg(Id)).section(' ', 3, 3).trimmed().toUpper() == getMyself().toUpper() )
461 skypeMessage(QString("CHATMESSAGE %1 STATUS SENT").arg(Id));//this message is from current user, so it is outcomming
462 else
463 skypeMessage(QString("CHATMESSAGE %1 STATUS RECEIVED").arg(Id));//simulate incoming message notification
464 }
465 }
466 } else if (messageType == "CALL") {
467 const QString &callId = message.section(' ', 1, 1).trimmed();
468 if (message.section(' ', 2, 2).trimmed().toUpper() == "CONF_ID") {
469 if (!d->knownCalls.contains(callId)) {//new call
470 d->knownCalls << callId;
471 const QString &userId = (d->connection % QString("GET CALL %1 PARTNER_HANDLE").arg(callId)).section(' ', 3, 3).trimmed();
472 emit newCall(callId, userId);
473 }
474 const QString &confId = message.section(' ', 3, 3).trimmed().toUpper();
475 if (confId != "0") {//It is an conference
476 emit groupCall(callId, confId);
477 }
478 }
479 if (message.section(' ', 2, 2).trimmed().toUpper() == "STATUS") {
480 if (!d->knownCalls.contains(callId)) {//new call
481 d->knownCalls << callId;
482 const QString &userId = (d->connection % QString("GET CALL %1 PARTNER_HANDLE").arg(callId)).section(' ', 3, 3).trimmed();
483 emit newCall(callId, userId);
484 }
485 const QString &status = message.section(' ', 3, 3).trimmed().toUpper();
486 if (status == "FAILED") {
487 int reason = (d->connection % QString("GET CALL %1 FAILUREREASON").arg(callId)).section(' ', 3, 3).trimmed().toInt();
488 QString errorText = i18n("Unknown error");
489 switch (reason) {
490 case 1:
491 errorText = i18n("Misc error");
492 break;
493 case 2:
494 errorText = i18n("User or phone number does not exist");
495 break;
496 case 3:
497 errorText = i18n("User is offline");
498 break;
499 case 4:
500 errorText = i18n("No proxy found");
501 break;
502 case 5:
503 errorText = i18n("Session terminated");
504 break;
505 case 6:
506 errorText = i18n("No common codec found");
507 break;
508 case 7:
509 errorText = i18n("Sound I/O error");
510 break;
511 case 8:
512 errorText = i18n("Problem with remote sound device");
513 break;
514 case 9:
515 errorText = i18n("Call blocked by recipient");
516 break;
517 case 10:
518 errorText = i18n("Recipient not a friend");
519 break;
520 case 11:
521 errorText = i18n("User not authorized by recipient");
522 break;
523 case 12:
524 errorText = i18n("Sound recording error");
525 break;
526 }
527 emit callError(callId, errorText);
528 }
529 emit callStatus(callId, status);
530 } else if ( message.section(' ', 2, 2).trimmed().toUpper() == "VIDEO_RECEIVE_STATUS" ) {
531 const QString &status = message.section(' ', 3, 3).trimmed().toUpper();
532 if ( status == "RUNNING" ) {
533 kDebug(SKYPE_DEBUG_GLOBAL) << "Start receiving video";
534 emit startReceivingVideo(callId);
535 } else if ( status == "STOPPING" ) {
536 kDebug(SKYPE_DEBUG_GLOBAL) << "Stop receiving video";
537 emit stopReceivingVideo(callId);
538 }
539 }
540 } else if (messageType == "CURRENTUSERHANDLE") {
541 QString user = message.section(' ', 1, 1).trimmed();
542 QString name = (d->connection % QString("GET USER %1 DISPLAYNAME").arg(user)).section(' ', 3).trimmed();
543 if (name.isEmpty())
544 name = (d->connection % QString("GET USER %1 FULLNAME").arg(user)).section(' ', 3).trimmed();
545 if (name.isEmpty())
546 name = user;
547 emit setMyselfName(name);
548 } else if (messageType == "PONG") {
549 // Do nothing
550 } else {
551 kDebug(SKYPE_DEBUG_GLOBAL) << "Unknown message" << message << "of type" << messageType;
552 }
553 }
554
getContactBuddy(const QString & contact)555 void Skype::getContactBuddy(const QString &contact) {
556 kDebug(SKYPE_DEBUG_GLOBAL);
557
558 d->connection << QString("GET USER %1 BUDDYSTATUS").arg(contact);//just make a message asking for the buddystatus of user and send it
559 }
560
resetStatus()561 void Skype::resetStatus() {
562 kDebug(SKYPE_DEBUG_GLOBAL);
563
564 switch (d->connStatus) {
565 case csOffline:
566 case csLoggedOut:
567 emit wentOffline();//Do not care what is the user marked as, this is more importatnt
568 return;
569 case csConnecting:
570 //if (d->onlineStatus == usOffline)//not connecting, user wants to be offline
571 // break;
572 emit statusConnecting();//still connecting, wait a minute
573 return;
574 default://just remove the compile-time warning about not handled value
575 break;
576 }
577
578 switch (d->onlineStatus) {
579 case usUnknown:
580 emit statusConnecting();
581 break;
582 case usOffline:
583 //emit wentOffline(); //We got onlineStatus usOffline too, when connStatus is csConnecting
584 break;
585 case usOnline:
586 emit wentOnline();
587 break;
588 case usSkypeMe:
589 emit wentSkypeMe();
590 break;
591 case usAway:
592 emit wentAway();
593 break;
594 case usNA:
595 emit wentNotAvailable();
596 break;
597 case usDND:
598 emit wentDND();
599 break;
600 case usInvisible:
601 emit wentInvisible();
602 break;
603 }
604 }
605
search(const QString & what)606 void Skype::search(const QString &what) {
607 kDebug(SKYPE_DEBUG_GLOBAL);
608
609 d->searchFor = what.section(' ', 0, 0).trimmed().toUpper();
610 d->connection << QString("SEARCH %1").arg(what.toUpper());//search for that
611 }
612
getContactInfo(const QString & contact)613 void Skype::getContactInfo(const QString &contact) {
614 kDebug(SKYPE_DEBUG_GLOBAL);
615
616 d->connection << QString("GET USER %1 FULLNAME").arg(contact)//ask for full name
617 << QString("GET USER %1 SEX").arg(contact)//ask for sex
618 << QString("GET USER %1 DISPLAYNAME").arg(contact)
619 << QString("GET USER %1 PHONE_HOME").arg(contact)
620 << QString("GET USER %1 PHONE_OFFICE").arg(contact)
621 << QString("GET USER %1 PHONE_MOBILE").arg(contact)
622 << QString("GET USER %1 ONLINESTATUS").arg(contact)
623 << QString("GET USER %1 HOMEPAGE").arg(contact)
624 << QString("GET USER %1 BUDDYSTATUS").arg(contact);//and the rest of info
625 }
626
canComunicate()627 bool Skype::canComunicate() {
628 return d->connection.connected();
629 }
630
setHitchMode(bool value)631 void Skype::setHitchMode(bool value) {
632 d->hitch = value;
633 }
634
setMarkMode(bool value)635 void Skype::setMarkMode(bool value) {
636 d->mark = value;
637 }
638
hitchHike(const QString & messageId)639 void Skype::hitchHike(const QString &messageId) {
640 kDebug(SKYPE_DEBUG_GLOBAL) << "Message: " << messageId;
641
642 const QString &chat = (d->connection % QString("GET CHATMESSAGE %1 CHATNAME").arg(messageId)).section(' ', 3, 3).trimmed();
643
644 const QString &chatType = (d->connection % QString("GET CHAT %1 STATUS").arg(chat)).section(' ', 3, 3).trimmed().toUpper();
645
646 bool ok = false;
647 uint utime = (d->connection % QString("GET CHATMESSAGE %1 TIMESTAMP").arg(messageId)).section(' ', 3, 3).trimmed().toUInt(&ok);
648 if ( ! ok )
649 utime = QDateTime::currentDateTime().toTime_t();
650
651 const QDateTime &timeStamp = QDateTime::fromTime_t(utime);
652
653 if ((chatType == "LEGACY_DIALOG") || (chatType == "DIALOG")) {
654
655 const QString &user = (d->connection % QString("GET CHATMESSAGE %1 FROM_HANDLE").arg(messageId)).section(' ', 3, 3).trimmed();//ask skype for a sender of that message and filter out the blouat around (like CHATMESSAGE 123...)
656
657 if ((d->hitch) || (d->account.userHasChat(user))) {//it can be read eather if the hitchhiking non-chat messages is enabled or if the user already has opened a chat
658 emit receivedIM(user, (d->connection % QString("GET CHATMESSAGE %1 BODY").arg(messageId)).section(' ', 3), messageId, timeStamp);//ask skype for the body and filter out the bload, we want only the text and make everyone aware that we received a message
659 if (d->mark) //We should mark it as read
660 d->connection << QString("SET CHATMESSAGE %1 SEEN").arg(messageId);//OK, just tell skype it is read
661 }
662 } else {
663 if ((d->hitch) || (d->account.chatExists(chat))) {
664 const QString &user = (d->connection % QString("GET CHATMESSAGE %1 FROM_HANDLE").arg(messageId)).section(' ', 3, 3).trimmed();
665 emit receivedMultiIM(chat, (d->connection % QString("GET CHATMESSAGE %1 BODY").arg(messageId)).section(' ', 3), messageId, user, timeStamp);
666 if (d->mark)
667 d->connection << QString("SET CHATMESSAGE %1 SEEN").arg(messageId);
668 }
669 }
670 }
671
send(const QString & user,const QString & message)672 QString Skype::send(const QString &user, const QString &message) {
673 kDebug(SKYPE_DEBUG_GLOBAL);
674
675 QString resp = d->connection % (QString("MESSAGE %1 %2").arg(user).arg(message));//just ask skype to send it
676
677 QString messageType = resp.section(' ', 0, 0).trimmed().toUpper();
678 if (messageType == "CHATMESSAGE") {
679 QString messageId = resp.section(' ', 1, 1).trimmed();
680 return messageId;
681 }
682 return QString();
683 }
684
editMessage(int messageId,const QString & newMessage)685 void Skype::editMessage(int messageId, const QString &newMessage) {
686 d->connection << QString("CHATMESSAGE %1 BODY %2").arg(messageId).arg(newMessage);
687 }
688
setScanForUnread(bool value)689 void Skype::setScanForUnread(bool value) {
690 d->scanForUnread = value;
691 }
692
makeCall(const QString & userId)693 void Skype::makeCall(const QString &userId) {
694 kDebug(SKYPE_DEBUG_GLOBAL);
695
696 d->connection << QString("CALL %1").arg(userId);
697 }
698
acceptCall(const QString & callId)699 void Skype::acceptCall(const QString &callId) {
700 kDebug(SKYPE_DEBUG_GLOBAL);
701
702 d->connection << QString("SET CALL %1 STATUS INPROGRESS").arg(callId);
703 }
704
hangUp(const QString & callId)705 void Skype::hangUp(const QString &callId) {
706 kDebug(SKYPE_DEBUG_GLOBAL);
707
708 d->connection << QString("SET CALL %1 STATUS FINISHED").arg(callId);
709 }
710
toggleHoldCall(const QString & callId)711 void Skype::toggleHoldCall(const QString &callId) {
712 kDebug(SKYPE_DEBUG_GLOBAL);
713
714 const QString &status = (d->connection % QString("GET CALL %1 STATUS").arg(callId)).section(' ', 3, 3).trimmed().toUpper();
715 if ((status == "ONHOLD") || (status == "LOCALHOLD"))
716 d->connection << QString("SET CALL %1 STATUS INPROGRESS").arg(callId);
717 else
718 d->connection << QString("SET CALL %1 STATUS ONHOLD").arg(callId);
719 }
720
isCallIncoming(const QString & callId)721 bool Skype::isCallIncoming(const QString &callId) {
722 const QString &type = (d->connection % QString("GET CALL %1 TYPE").arg(callId)).section(' ', 3, 3).trimmed().toUpper();
723 return ((type == "INCOMING_P2P") || (type == "INCOMING_PSTN"));
724 }
725
getSkypeOut()726 void Skype::getSkypeOut() {
727 const QString &curr = (d->connection % QString("GET PROFILE PSTN_BALANCE_CURRENCY")).section(' ', 2, 2).trimmed().toUpper();
728 if (curr.isEmpty()) {
729 emit skypeOutInfo(0, "");
730 } else {
731 int value = (d->connection % QString("GET PROFILE PSTN_BALANCE")).section(' ', 2, 2).trimmed().toInt();
732 emit skypeOutInfo(value, curr);
733 }
734 }
735
enablePings(bool enabled)736 void Skype::enablePings(bool enabled) {
737 kDebug(SKYPE_DEBUG_GLOBAL);
738
739 d->pings = enabled;
740
741 if (!enabled) {
742 d->pingTimer->stop();
743 return;
744 }
745
746 if (d->connStatus != csOffline) {
747 d->pingTimer->start(1000);
748 }
749 }
750
ping()751 void Skype::ping() {
752 d->connection << QString("PING");
753 }
754
setBus(int bus)755 void Skype::setBus(int bus) {
756 d->bus = bus;
757 }
758
setLaunchTimeout(int seconds)759 void Skype::setLaunchTimeout(int seconds) {
760 d->launchTimeout = seconds;
761 }
762
setSkypeCommand(const QString & command)763 void Skype::setSkypeCommand(const QString &command) {
764 d->skypeCommand = command;
765 }
766
setWaitConnect(int value)767 void Skype::setWaitConnect(int value) {
768 d->waitBeforeConnect = value;
769 }
770
sendToChat(const QString & chat,const QString & message)771 QString Skype::sendToChat(const QString &chat, const QString &message) {
772 kDebug(SKYPE_DEBUG_GLOBAL);
773
774 QString resp = d->connection % (QString("CHATMESSAGE %1 %2").arg(chat).arg(message));
775
776 QString messageType = resp.section(' ', 0, 0).trimmed().toUpper();
777 if (messageType == "CHATMESSAGE") {
778 QString messageId = resp.section(' ', 1, 1).trimmed();
779 return messageId;
780 }
781 return QString();
782 }
783
getTopic(const QString & chat)784 void Skype::getTopic(const QString &chat) {
785 kDebug(SKYPE_DEBUG_GLOBAL);
786
787 emit setTopic(chat, (d->connection % QString("GET CHAT %1 FRIENDLYNAME").arg(chat)).section(' ', 3).trimmed());
788 }
789
getMessageChat(const QString & message)790 QString Skype::getMessageChat(const QString &message) {
791 kDebug(SKYPE_DEBUG_GLOBAL);
792
793 return (d->connection % QString("GET CHATMESSAGE %1 CHATNAME").arg(message)).section(' ', 3, 3).trimmed();
794 }
795
getChatUsers(const QString & chat)796 QStringList Skype::getChatUsers(const QString &chat) {
797 kDebug(SKYPE_DEBUG_GLOBAL);
798
799 const QString &me = getMyself();
800 const QString &rawUsers = (d->connection % QString("GET CHAT %1 MEMBERS").arg(chat)).section(' ', 3).trimmed();
801 const QStringList &users = rawUsers.split(' ');
802 QStringList readyUsers;
803 for (QStringList::const_iterator it = users.begin(); it != users.end(); ++it) {
804 const QString &user = (*it).trimmed();
805 if (user.toUpper() != me.toUpper())
806 readyUsers.append(user);
807 }
808
809 return readyUsers;
810 }
811
getMyself()812 QString Skype::getMyself() {
813 return (d->connection % QString("GET CURRENTUSERHANDLE")).section(' ', 1, 1).trimmed();
814 }
815
inviteUser(const QString & chatId,const QString & userId)816 void Skype::inviteUser(const QString &chatId, const QString &userId) {
817 kDebug(SKYPE_DEBUG_GLOBAL) << chatId << userId;
818
819 if (d->connection.protocolVer() <= 4) {
820 KMessageBox::error(0L, i18n("This version of Skype does not support adding users to chat."), i18n("Skype Protocol"));
821 return;
822 }
823
824 d->connection << QString("ALTER CHAT %1 ADDMEMBERS %2").arg(chatId).arg(userId);
825 }
826
createChat(const QString & users)827 QString Skype::createChat(const QString &users) {
828 kDebug(SKYPE_DEBUG_GLOBAL);
829
830 const QString &chatDesc = d->connection % QString("CHAT CREATE %1").arg(users);
831 kDebug(SKYPE_DEBUG_GLOBAL) << "New chat ID: " << chatDesc.section(' ', 1, 1);
832 return chatDesc.section(' ', 1, 1);
833 }
834
leaveChat(const QString & chatId)835 void Skype::leaveChat(const QString &chatId) {
836 kDebug(SKYPE_DEBUG_GLOBAL);
837
838 d->connection << QString("ALTER CHAT %1 LEAVE").arg(chatId);
839 }
840
removeContact(const QString & contactId)841 void Skype::removeContact(const QString &contactId) {
842 kDebug(SKYPE_DEBUG_GLOBAL);
843
844 d->connection << QString("SET USER %1 BUDDYSTATUS 1").arg(contactId);
845 }
846
addContact(const QString & contactId)847 void Skype::addContact(const QString &contactId) {
848 kDebug(SKYPE_DEBUG_GLOBAL);
849
850 d->connection % QString("SET USER %1 BUDDYSTATUS 2").arg(contactId);//do NOT parse this so the contact won't be created automatically
851 }
852
setAuthor(const QString & contactId,AuthorType author)853 void Skype::setAuthor(const QString &contactId, AuthorType author) {
854 kDebug(SKYPE_DEBUG_GLOBAL);
855
856 switch (author) {
857 case Author:
858 d->connection << QString("SET USER %1 ISBLOCKED FALSE").arg(contactId);
859 d->connection << QString("SET USER %1 ISAUTHORIZED TRUE").arg(contactId);
860 break;
861 case Deny:
862 d->connection << QString("SET USER %1 ISBLOCKED FALSE").arg(contactId);
863 d->connection << QString("SET USER %1 ISAUTHORIZED FALSE").arg(contactId);
864 break;
865 case Block:
866 d->connection << QString("SET USER %1 ISBLOCKED TRUE").arg(contactId);
867 break;
868 }
869 }
870
getAuthor(const QString & contactId)871 Skype::AuthorType Skype::getAuthor(const QString &contactId) {
872 kDebug(SKYPE_DEBUG_GLOBAL);
873 if ((d->connection % QString("GET USER %1 ISBLOCKED").arg(contactId)).section(' ', 3, 3).trimmed().toUpper() == "TRUE")
874 return Block;
875 else if ((d->connection % QString("GET USER %1 ISAUTHORIZED").arg(contactId)).section(' ', 3, 3).trimmed().toUpper() == "TRUE")
876 return Author;
877 else
878 return Deny;
879 }
880
ableConference()881 bool Skype::ableConference() {
882 kDebug(SKYPE_DEBUG_GLOBAL);
883 return false;
884 }
885
fixGroups(bool loadOnly)886 void Skype::fixGroups(bool loadOnly) {
887 kDebug(SKYPE_DEBUG_GLOBAL);
888
889 d->groupsContacts.clear();//remove all contacts and groups in memory
890 d->groupsNames.clear();//remove all groups names
891
892 //Fill d->groupsNames
893 {
894 QStringList groups = QString(d->connection % "SEARCH GROUPS CUSTOM").section(' ', 1).trimmed().split(", ");//get all ids of group
895
896 for ( QStringList::iterator it = groups.begin(); it != groups.end(); ++it ){
897 if ( ! (*it).trimmed().isEmpty() ){
898 int groupID = (*it).trimmed().toInt();
899 QString groupName = (d->connection % QString("GET GROUP %1 DISPLAYNAME").arg(groupID)).section(' ', 3).trimmed();
900 kDebug(SKYPE_DEBUG_GLOBAL) << "Adding to memory group" << groupID << ":" << groupName;
901 d->groupsNames.insert(groupName, groupID);
902 }
903 }
904 }
905
906 //Fill d->groupsContacts
907 //Remove empty groups
908 if ( d->groupsNames.count() > 0 ) {
909 QList <int> groups = d->groupsNames.values();
910 for ( QList <int>::iterator group = groups.begin(); group != groups.end(); ++group ) {
911 QStringList groupusers = QString(d->connection % QString("GET GROUP %1 USERS").arg(*group)).section(' ', 3).trimmed().split(", ");//get all user in group (*group)
912 if ( ( groupusers.count() == 0 || groupusers.first().trimmed().isEmpty() ) && ! loadOnly ) {//if group is empty, delete it
913 kDebug(SKYPE_DEBUG_GLOBAL) << QString("Group %1 is empty, delete it").arg(*group);
914 deleteGroup(*group);
915 } else {
916 kDebug(SKYPE_DEBUG_GLOBAL) << QString("Group %1 has users:").arg(*group) << groupusers;
917 for ( QStringList::iterator user = groupusers.begin(); user != groupusers.end(); ++user ) {//search for all users in group (*group)
918 if ( ! (*user).trimmed().isEmpty() ){//if username isnt empty add it to group
919 kDebug(SKYPE_DEBUG_GLOBAL) << "Adding user " << (*user).trimmed() << "to memory group" << *group << ":" << d->groupsNames.key(*group);
920 d->groupsContacts.insert( *group, (*user).trimmed() );//add user (*user) to group (*group)
921 }
922 }
923 }
924 }
925 }
926
927 //Check if user is only in one group
928 if ( ! loadOnly ){
929 QStringList users = d->groupsContacts.values();//get all users from all groups
930 for ( QStringList::iterator user = users.begin(); user != users.end(); ++user ) {
931 if ( ! (*user).isEmpty() ) {
932 QList <int> groups = d->groupsContacts.keys(*user);//get groups for user (*user)
933 kDebug(SKYPE_DEBUG_GLOBAL) << QString("User %1 is in memory groups:").arg(*user) << groups;
934 if ( groups.count() > 1 ) {//if user is in more then one group, remove it from all groups except first
935 for ( QList <int>::iterator group = groups.begin()+1; group != groups.end(); ++group ){
936 kDebug(SKYPE_DEBUG_GLOBAL) << QString("User %1 is in more then one memory groups, removing from memory group %2").arg(*user).arg(*group);
937 removeFromGroup(*user, *group);
938 }
939 }
940 }
941 }
942 }
943
944 //Check if groups do not have same names
945 if ( ! loadOnly ) {
946 QStringList groupsNames = d->groupsNames.keys();//get all groups names, if group has more ides then one, add to List this group only one
947 for ( QStringList::iterator group = groupsNames.begin(); group != groupsNames.end(); ++group ){
948 QList <int> groupIdes = d->groupsNames.values(*group);
949 if ( groupIdes.count() > 1 ){
950 kDebug(SKYPE_DEBUG_GLOBAL) << "Group" << *group << "has more ides then one:" << groupIdes << ", so merge all these groups to" << groupIdes.last();
951 for ( QList <int>::iterator groupID = groupIdes.begin(); groupID != groupIdes.end() - 1; ++groupID ) {
952 QStringList users = d->groupsContacts.values(*groupID);
953 for ( QStringList::iterator user = users.begin(); user != users.end(); ++user ) {
954 removeFromGroup((*user), (*groupID));
955 addToGroup((*user), groupIdes.last());
956 }
957 deleteGroup(*groupID);
958 }
959 groupsNames.removeAll(*group);
960 }
961 }
962 }
963
964 }
965
getContactGroupID(const QString & name)966 int Skype::getContactGroupID(const QString &name) {
967 kDebug(SKYPE_DEBUG_GLOBAL) << name;
968 return d->groupsContacts.key(name, -1); //get group id from d->groupsContacts
969 }
970
removeFromGroup(const QString & name,int groupID)971 void Skype::removeFromGroup(const QString &name, int groupID) {
972 kDebug(SKYPE_DEBUG_GLOBAL) << name << groupID;
973 d->connection << QString("ALTER GROUP %1 REMOVEUSER %2").arg(groupID).arg(name);
974 d->groupsContacts.remove(groupID, name);
975 }
976
addToGroup(const QString & name,int groupID)977 void Skype::addToGroup(const QString &name, int groupID) {
978 kDebug(SKYPE_DEBUG_GLOBAL) << name << groupID;
979 d->connection << QString("ALTER GROUP %1 ADDUSER %2").arg(groupID).arg(name);
980 d->groupsContacts.insert(groupID, name);
981 }
982
createGroup(const QString & name)983 void Skype::createGroup(const QString &name) {
984 kDebug(SKYPE_DEBUG_GLOBAL) << name;
985 d->connection << QString("CREATE GROUP %1").arg(name);
986 fixGroups(true); ///TODO: Find better way to get group id and create memory group too without fixGroups()
987 }
988
deleteGroup(int groupID)989 void Skype::deleteGroup(int groupID) {
990 kDebug(SKYPE_DEBUG_GLOBAL) << groupID << ":" << d->groupsNames.key(groupID);
991 d->connection << QString("DELETE GROUP %1").arg(groupID);
992 d->groupsNames.remove(d->groupsNames.key(groupID), groupID);
993 d->groupsContacts.remove(groupID);
994 }
995
renameGroup(int groupID,const QString & newName)996 void Skype::renameGroup(int groupID, const QString &newName) {
997 kDebug(SKYPE_DEBUG_GLOBAL) << groupID;
998 d->connection << QString("SET GROUP %1 DISPLAYNAME %2").arg(groupID).arg(newName);
999 d->groupsNames.remove(d->groupsNames.key(groupID));
1000 d->groupsNames.insert(newName, groupID);
1001 }
1002
getGroupID(const QString & groupname)1003 int Skype::getGroupID(const QString &groupname) {
1004 kDebug(SKYPE_DEBUG_GLOBAL) << groupname;
1005 return d->groupsNames.value(groupname, -1); //get group id from d->groupsNames
1006 }
1007
getGroupName(int groupID)1008 QString Skype::getGroupName(int groupID) {
1009 kDebug(SKYPE_DEBUG_GLOBAL) << groupID;
1010
1011 if (groupID == -1) //If groupID is empty return empty name
1012 return QString();
1013
1014 return d->groupsNames.key(groupID, QString()); //get group name from d->groupsNames
1015 }
1016
getContactDisplayName(const QString & user)1017 QString Skype::getContactDisplayName(const QString &user) {
1018 kDebug(SKYPE_DEBUG_GLOBAL) << user;
1019 return (d->connection % QString("GET USER %1 DISPLAYNAME").arg(user)).section(' ', 3).trimmed();
1020 }
1021
setContactDisplayName(const QString & user,const QString & name)1022 void Skype::setContactDisplayName(const QString &user, const QString &name) {
1023 kDebug(SKYPE_DEBUG_GLOBAL);
1024 d->connection % QString("SET USER %1 DISPLAYNAME %2").arg(user).arg(name);
1025 }
1026
openFileTransfer(const QString & user,const QString & url)1027 bool Skype::openFileTransfer(const QString &user, const QString &url) {
1028 kDebug(SKYPE_DEBUG_GLOBAL) << user << url;
1029 if ( (d->connection % QString("OPEN FILETRANSFER %1 IN %2").arg(user).arg(url)).trimmed() == "OK" )
1030 return true;
1031 else
1032 return false;
1033 }
1034
searchUsers(const QString & string)1035 QStringList Skype::searchUsers(const QString &string) {
1036 kDebug(SKYPE_DEBUG_GLOBAL) << string;
1037 return (d->connection % QString("SEARCH USERS %1").arg(string)).section(' ', 1).trimmed().split(' ');
1038 }
1039
supportVideo(const QString & user)1040 bool Skype::supportVideo(const QString &user) {
1041 kDebug(SKYPE_DEBUG_GLOBAL) << user;
1042 if ( (d->connection % QString("GET USER %1 IS_VIDEO_CAPABLE").arg(user)).section(' ', 3).trimmed().toUpper() == "TRUE" )
1043 return true;
1044 else
1045 return false;
1046 }
1047
startSendingVideo(const QString & callId)1048 void Skype::startSendingVideo(const QString &callId) {
1049 kDebug(SKYPE_DEBUG_GLOBAL) << callId;
1050 d->connection << QString("ALTER CALL %1 START_VIDEO_SEND").arg(callId);
1051 }
1052
stopSendingVideo(const QString & callId)1053 void Skype::stopSendingVideo(const QString &callId) {
1054 kDebug(SKYPE_DEBUG_GLOBAL) << callId;
1055 d->connection << QString("ALTER CALL %1 STOP_VIDEO_SEND").arg(callId);
1056 }
1057
1058