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