source: skype/skype.c @ a317ba6

Last change on this file since a317ba6 was a317ba6, checked in by Miklos Vajna <vmiklos@…>, at 2008-03-31T00:20:33Z

skype_set_call(): allow calling the test girl

  • Property mode set to 100644
File size: 33.0 KB
Line 
1/*
2 *  skype.c - Skype plugin for BitlBee
3 *
4 *  Copyright (c) 2007, 2008 by Miklos Vajna <vmiklos@frugalware.org>
5 *
6 *  Several ideas are used from the BitlBee Jabber plugin, which is
7 *
8 *  Copyright (c) 2006 by Wilmer van der Gaast <wilmer@gaast.net>
9 *
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License as published by
12 *  the Free Software Foundation; either version 2 of the License, or
13 *  (at your option) any later version.
14 *
15 *  This program is distributed in the hope that it will be useful,
16 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 *  GNU General Public License for more details.
19 *
20 *  You should have received a copy of the GNU General Public License
21 *  along with this program; if not, write to the Free Software
22 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
23 *  USA.
24 */
25
26#define _XOPEN_SOURCE
27#include <stdio.h>
28#include <poll.h>
29#include <bitlbee.h>
30#include <bitlbee/ssl_client.h>
31#include <glib.h>
32
33#define SKYPE_DEFAULT_SERVER "localhost"
34#define SKYPE_DEFAULT_PORT "2727"
35
36/*
37 * Enumerations
38 */
39
40typedef enum
41{
42        SKYPE_CALL_RINGING = 1,
43        SKYPE_CALL_MISSED,
44        SKYPE_CALL_CANCELLED,
45        SKYPE_CALL_FINISHED,
46        SKYPE_CALL_REFUSED
47} skype_call_status;
48
49typedef enum
50{
51        SKYPE_FILETRANSFER_NEW = 1,
52        SKYPE_FILETRANSFER_FAILED
53} skype_filetransfer_status;
54
55/*
56 * Structures
57 */
58
59struct skype_data
60{
61        struct im_connection *ic;
62        char *username;
63        /* The effective file descriptor. We store it here so any function can
64         * write() to it. */
65        int fd;
66        /* File descriptor returned by bitlbee. we store it so we know when
67         * we're connected and when we aren't. */
68        int bfd;
69        /* ssl_getfd() uses this to get the file desciptor. */
70        void *ssl;
71        /* When we receive a new message id, we query the properties, finally
72         * the chatname. Store the properties here so that we can use
73         * imcb_buddy_msg() when we got the chatname. */
74        char *handle;
75        /* List, because of multiline messages. */
76        GList *body;
77        char *type;
78        /* This is necessary because we send a notification when we get the
79         * handle. So we store the state here and then we can send a
80         * notification about the handle is in a given status. */
81        skype_call_status call_status;
82        char *call_id;
83        char *call_duration;
84        /* If the call is outgoing or not */
85        int call_out;
86        /* Same for file transfers. */
87        skype_filetransfer_status filetransfer_status;
88        /* Using /j #nick we want to have a groupchat with two people. Usually
89         * not (default). */
90        char* groupchat_with;
91        /* The user who invited us to the chat. */
92        char* adder;
93        /* If we are waiting for a confirmation about we changed the topic. */
94        int topic_wait;
95        /* These are used by the info command. */
96        char *info_fullname;
97        char *info_phonehome;
98        char *info_phoneoffice;
99        char *info_phonemobile;
100        char *info_nrbuddies;
101        char *info_tz;
102        char *info_seen;
103        char *info_birthday;
104        char *info_sex;
105        char *info_language;
106        char *info_country;
107        char *info_province;
108        char *info_city;
109        char *info_homepage;
110        char *info_about;
111};
112
113struct skype_away_state
114{
115        char *code;
116        char *full_name;
117};
118
119struct skype_buddy_ask_data
120{
121        struct im_connection *ic;
122        /* This is also used for call IDs for simplicity */
123        char *handle;
124};
125
126/*
127 * Tables
128 */
129
130const struct skype_away_state skype_away_state_list[] =
131{
132        { "ONLINE",  "Online" },
133        { "SKYPEME",  "Skype Me" },
134        { "AWAY",   "Away" },
135        { "NA",    "Not available" },
136        { "DND",      "Do Not Disturb" },
137        { "INVISIBLE",      "Invisible" },
138        { "OFFLINE",      "Offline" },
139        { NULL, NULL}
140};
141
142/*
143 * Functions
144 */
145
146int skype_write( struct im_connection *ic, char *buf, int len )
147{
148        struct skype_data *sd = ic->proto_data;
149        struct pollfd pfd[1];
150
151        pfd[0].fd = sd->fd;
152        pfd[0].events = POLLOUT;
153
154        /* This poll is necessary or we'll get a SIGPIPE when we write() to
155         * sd->fd. */
156        poll(pfd, 1, 1000);
157        if(pfd[0].revents & POLLHUP)
158        {
159                imc_logout( ic, TRUE );
160                return FALSE;
161        }
162        ssl_write( sd->ssl, buf, len );
163
164        return TRUE;
165}
166
167static void skype_buddy_ask_yes( gpointer w, struct skype_buddy_ask_data *bla )
168{
169        char *buf = g_strdup_printf("SET USER %s ISAUTHORIZED TRUE", bla->handle);
170        skype_write( bla->ic, buf, strlen( buf ) );
171        g_free(buf);
172        g_free(bla->handle);
173        g_free(bla);
174}
175
176static void skype_buddy_ask_no( gpointer w, struct skype_buddy_ask_data *bla )
177{
178        char *buf = g_strdup_printf("SET USER %s ISAUTHORIZED FALSE", bla->handle);
179        skype_write( bla->ic, buf, strlen( buf ) );
180        g_free(buf);
181        g_free(bla->handle);
182        g_free(bla);
183}
184
185void skype_buddy_ask( struct im_connection *ic, char *handle, char *message)
186{
187        struct skype_buddy_ask_data *bla = g_new0( struct skype_buddy_ask_data, 1 );
188        char *buf;
189
190        bla->ic = ic;
191        bla->handle = g_strdup(handle);
192
193        buf = g_strdup_printf( "The user %s wants to add you to his/her buddy list, saying: '%s'.", handle, message);
194        imcb_ask( ic, buf, bla, skype_buddy_ask_yes, skype_buddy_ask_no );
195        g_free( buf );
196}
197
198static void skype_call_ask_yes( gpointer w, struct skype_buddy_ask_data *bla )
199{
200        char *buf = g_strdup_printf("SET CALL %s STATUS INPROGRESS", bla->handle);
201        skype_write( bla->ic, buf, strlen( buf ) );
202        g_free(buf);
203        g_free(bla->handle);
204        g_free(bla);
205}
206
207static void skype_call_ask_no( gpointer w, struct skype_buddy_ask_data *bla )
208{
209        char *buf = g_strdup_printf("SET CALL %s STATUS FINISHED", bla->handle);
210        skype_write( bla->ic, buf, strlen( buf ) );
211        g_free(buf);
212        g_free(bla->handle);
213        g_free(bla);
214}
215
216void skype_call_ask( struct im_connection *ic, char *call_id, char *message)
217{
218        struct skype_buddy_ask_data *bla = g_new0( struct skype_buddy_ask_data, 1 );
219
220        bla->ic = ic;
221        bla->handle = g_strdup(call_id);
222
223        imcb_ask( ic, message, bla, skype_call_ask_yes, skype_call_ask_no );
224}
225struct groupchat *skype_chat_by_name( struct im_connection *ic, char *name )
226{
227        struct groupchat *ret;
228
229        for( ret = ic->groupchats; ret; ret = ret->next )
230        {
231                if(strcmp(name, ret->title ) == 0 )
232                        break;
233        }
234
235        return ret;
236}
237
238static gboolean skype_read_callback( gpointer data, gint fd, b_input_condition cond )
239{
240        struct im_connection *ic = data;
241        struct skype_data *sd = ic->proto_data;
242        char buf[1024];
243        int st;
244        char **lines, **lineptr, *line, *ptr;
245
246        if( !sd || sd->fd == -1 )
247                return FALSE;
248        /* Read the whole data. */
249        st = ssl_read( sd->ssl, buf, sizeof( buf ) );
250        if( st > 0 )
251        {
252                buf[st] = '\0';
253                /* Then split it up to lines. */
254                lines = g_strsplit(buf, "\n", 0);
255                lineptr = lines;
256                while((line = *lineptr))
257                {
258                        if(!strlen(line))
259                                break;
260                        if(!strncmp(line, "USERS ", 6))
261                        {
262                                char **i;
263                                char **nicks;
264
265                                nicks = g_strsplit(line + 6, ", ", 0);
266                                i = nicks;
267                                while(*i)
268                                {
269                                        g_snprintf(buf, 1024, "GET USER %s ONLINESTATUS\n", *i);
270                                        skype_write( ic, buf, strlen( buf ) );
271                                        i++;
272                                }
273                                g_strfreev(nicks);
274                        }
275                        else if(!strncmp(line, "USER ", 5))
276                        {
277                                int flags = 0;
278                                char *status = strrchr(line, ' ');
279                                char *user = strchr(line, ' ');
280                                status++;
281                                ptr = strchr(++user, ' ');
282                                *ptr = '\0';
283                                ptr++;
284                                if(!strncmp(ptr, "ONLINESTATUS ", 13) &&
285                                                strcmp(user, sd->username) != 0
286                                                && strcmp(user, "echo123") != 0)
287                                {
288                                        ptr = g_strdup_printf("%s@skype.com", user);
289                                        imcb_add_buddy(ic, ptr, NULL);
290                                        if(strcmp(status, "OFFLINE") != 0)
291                                                flags |= OPT_LOGGED_IN;
292                                        if(strcmp(status, "ONLINE") != 0 && strcmp(status, "SKYPEME") != 0)
293                                                flags |= OPT_AWAY;
294                                        imcb_buddy_status(ic, ptr, flags, NULL, NULL);
295                                        g_free(ptr);
296                                }
297                                else if(!strncmp(ptr, "RECEIVEDAUTHREQUEST ", 20))
298                                {
299                                        char *message = ptr + 20;
300                                        if(strlen(message))
301                                                skype_buddy_ask(ic, user, message);
302                                }
303                                else if(!strncmp(ptr, "BUDDYSTATUS ", 12))
304                                {
305                                        char *st = ptr + 12;
306                                        if(!strcmp(st, "3"))
307                                        {
308                                                char *buf = g_strdup_printf("%s@skype.com", user);
309                                                imcb_add_buddy(ic, buf, NULL);
310                                                g_free(buf);
311                                        }
312                                }
313                                else if(!strncmp(ptr, "FULLNAME ", 9))
314                                        sd->info_fullname = g_strdup_printf("%s", ptr + 9);
315                                else if(!strncmp(ptr, "PHONE_HOME ", 11))
316                                        sd->info_phonehome = g_strdup_printf("%s", ptr + 11);
317                                else if(!strncmp(ptr, "PHONE_OFFICE ", 13))
318                                        sd->info_phoneoffice = g_strdup_printf("%s", ptr + 13);
319                                else if(!strncmp(ptr, "PHONE_MOBILE ", 13))
320                                        sd->info_phonemobile = g_strdup_printf("%s", ptr + 13);
321                                else if(!strncmp(ptr, "NROF_AUTHED_BUDDIES ", 20))
322                                        sd->info_nrbuddies = g_strdup_printf("%s", ptr + 20);
323                                else if(!strncmp(ptr, "TIMEZONE ", 9))
324                                        sd->info_tz = g_strdup_printf("%s", ptr + 9);
325                                else if(!strncmp(ptr, "LASTONLINETIMESTAMP ", 20))
326                                        sd->info_seen = g_strdup_printf("%s", ptr + 20);
327                                else if(!strncmp(ptr, "BIRTHDAY ", 9))
328                                        sd->info_birthday = g_strdup_printf("%s", ptr + 9);
329                                else if(!strncmp(ptr, "SEX ", 4))
330                                        sd->info_sex = g_strdup_printf("%s", ptr + 4);
331                                else if(!strncmp(ptr, "LANGUAGE ", 9))
332                                        sd->info_language = g_strdup_printf("%s", ptr + 9);
333                                else if(!strncmp(ptr, "COUNTRY ", 8))
334                                        sd->info_country = g_strdup_printf("%s", ptr + 8);
335                                else if(!strncmp(ptr, "PROVINCE ", 9))
336                                        sd->info_province = g_strdup_printf("%s", ptr + 9);
337                                else if(!strncmp(ptr, "CITY ", 5))
338                                        sd->info_city = g_strdup_printf("%s", ptr + 5);
339                                else if(!strncmp(ptr, "HOMEPAGE ", 9))
340                                        sd->info_homepage = g_strdup_printf("%s", ptr + 9);
341                                else if(!strncmp(ptr, "ABOUT ", 6))
342                                {
343                                        sd->info_about = g_strdup_printf("%s", ptr + 6);
344
345                                        GString *st = g_string_new("Contact Information\n");
346                                        g_string_append_printf(st, "Skype Name: %s\n", user);
347                                        if(sd->info_fullname)
348                                        {
349                                                if(strlen(sd->info_fullname))
350                                                        g_string_append_printf(st, "Full Name: %s\n", sd->info_fullname);
351                                                g_free(sd->info_fullname);
352                                        }
353                                        if(sd->info_phonehome)
354                                        {
355                                                if(strlen(sd->info_phonehome))
356                                                        g_string_append_printf(st, "Home Phone: %s\n", sd->info_phonehome);
357                                                g_free(sd->info_phonehome);
358                                        }
359                                        if(sd->info_phoneoffice)
360                                        {
361                                                if(strlen(sd->info_phoneoffice))
362                                                        g_string_append_printf(st, "Office Phone: %s\n", sd->info_phoneoffice);
363                                                g_free(sd->info_phoneoffice);
364                                        }
365                                        if(sd->info_phonemobile)
366                                        {
367                                                if(strlen(sd->info_phonemobile))
368                                                        g_string_append_printf(st, "Mobile Phone: %s\n", sd->info_phonemobile);
369                                                g_free(sd->info_phonemobile);
370                                        }
371                                        g_string_append_printf(st, "Personal Information\n");
372                                        if(sd->info_nrbuddies)
373                                        {
374                                                if(strlen(sd->info_nrbuddies))
375                                                        g_string_append_printf(st, "Contacts: %s\n", sd->info_nrbuddies);
376                                                g_free(sd->info_nrbuddies);
377                                        }
378                                        if(sd->info_tz)
379                                        {
380                                                if(strlen(sd->info_tz))
381                                                {
382                                                        char ib[256];
383                                                        time_t t = time(NULL);
384                                                        t += atoi(sd->info_tz)-(60*60*24);
385                                                        struct tm *gt = gmtime(&t);
386                                                        strftime(ib, 256, "%H:%M:%S", gt);
387                                                        g_string_append_printf(st, "Local Time: %s\n", ib);
388                                                }
389                                                g_free(sd->info_tz);
390                                        }
391                                        if(sd->info_seen)
392                                        {
393                                                if(strlen(sd->info_seen))
394                                                {
395                                                        char ib[256];
396                                                        time_t it = atoi(sd->info_seen);
397                                                        struct tm *tm = localtime(&it);
398                                                        strftime(ib, 256, ("%Y. %m. %d. %H:%M"), tm);
399                                                        g_string_append_printf(st, "Last Seen: %s\n", ib);
400                                                }
401                                                g_free(sd->info_seen);
402                                        }
403                                        if(sd->info_birthday)
404                                        {
405                                                if(strlen(sd->info_birthday) && strcmp(sd->info_birthday, "0"))
406                                                {
407                                                        char ib[256];
408                                                        struct tm tm;
409                                                        strptime(sd->info_birthday, "%Y%m%d", &tm);
410                                                        strftime(ib, 256, "%B %d, %Y", &tm);
411                                                        g_string_append_printf(st, "Birthday: %s\n", ib);
412
413                                                        strftime(ib, 256, "%Y", &tm);
414                                                        int year = atoi(ib);
415                                                        time_t t = time(NULL);
416                                                        struct tm *lt = localtime(&t);
417                                                        g_string_append_printf(st, "Age: %d\n", lt->tm_year+1900-year);
418                                                }
419                                                g_free(sd->info_birthday);
420                                        }
421                                        if(sd->info_sex)
422                                        {
423                                                if(strlen(sd->info_sex))
424                                                {
425                                                        char *iptr = sd->info_sex;
426                                                        while(*iptr++)
427                                                                *iptr = tolower(*iptr);
428                                                        g_string_append_printf(st, "Gender: %s\n", sd->info_sex);
429                                                }
430                                                g_free(sd->info_sex);
431                                        }
432                                        if(sd->info_language)
433                                        {
434                                                if(strlen(sd->info_language))
435                                                {
436                                                        char *iptr = strchr(sd->info_language, ' ');
437                                                        if(iptr)
438                                                                iptr++;
439                                                        else
440                                                                iptr = sd->info_language;
441                                                        g_string_append_printf(st, "Language: %s\n", iptr);
442                                                }
443                                                g_free(sd->info_language);
444                                        }
445                                        if(sd->info_country)
446                                        {
447                                                if(strlen(sd->info_country))
448                                                {
449                                                        char *iptr = strchr(sd->info_country, ' ');
450                                                        if(iptr)
451                                                                iptr++;
452                                                        else
453                                                                iptr = sd->info_country;
454                                                        g_string_append_printf(st, "Country: %s\n", iptr);
455                                                }
456                                                g_free(sd->info_country);
457                                        }
458                                        if(sd->info_province)
459                                        {
460                                                if(strlen(sd->info_province))
461                                                        g_string_append_printf(st, "Region: %s\n", sd->info_province);
462                                                g_free(sd->info_province);
463                                        }
464                                        if(sd->info_city)
465                                        {
466                                                if(strlen(sd->info_city))
467                                                        g_string_append_printf(st, "City: %s\n", sd->info_city);
468                                                g_free(sd->info_city);
469                                        }
470                                        if(sd->info_homepage)
471                                        {
472                                                if(strlen(sd->info_homepage))
473                                                        g_string_append_printf(st, "Homepage: %s\n", sd->info_homepage);
474                                                g_free(sd->info_homepage);
475                                        }
476                                        if(sd->info_about)
477                                        {
478                                                if(strlen(sd->info_about))
479                                                        g_string_append_printf(st, "%s\n", sd->info_about);
480                                                g_free(sd->info_about);
481                                        }
482                                        imcb_log(ic, "%s", st->str);
483                                        g_string_free(st, TRUE);
484                                }
485                        }
486                        else if(!strncmp(line, "CHATMESSAGE ", 12))
487                        {
488                                char *id = strchr(line, ' ');
489                                if(++id)
490                                {
491                                        char *info = strchr(id, ' ');
492                                        *info = '\0';
493                                        info++;
494                                        if(!strcmp(info, "STATUS RECEIVED"))
495                                        {
496                                                /* New message ID:
497                                                 * (1) Request its from field
498                                                 * (2) Request its body
499                                                 * (3) Request its type
500                                                 * (4) Query chatname
501                                                 */
502                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s FROM_HANDLE\n", id);
503                                                skype_write( ic, buf, strlen( buf ) );
504                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s BODY\n", id);
505                                                skype_write( ic, buf, strlen( buf ) );
506                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s TYPE\n", id);
507                                                skype_write( ic, buf, strlen( buf ) );
508                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s CHATNAME\n", id);
509                                                skype_write( ic, buf, strlen( buf ) );
510                                        }
511                                        else if(!strncmp(info, "FROM_HANDLE ", 12))
512                                        {
513                                                info += 12;
514                                                /* New from field value. Store
515                                                 * it, then we can later use it
516                                                 * when we got the message's
517                                                 * body. */
518                                                g_free(sd->handle);
519                                                sd->handle = g_strdup_printf("%s@skype.com", info);
520                                        }
521                                        else if(!strncmp(info, "EDITED_BY ", 10))
522                                        {
523                                                info += 10;
524                                                /* This is the same as
525                                                 * FROM_HANDLE, except that we
526                                                 * never request these lines
527                                                 * from Skype, we just get
528                                                 * them. */
529                                                g_free(sd->handle);
530                                                sd->handle = g_strdup_printf("%s@skype.com", info);
531                                        }
532                                        else if(!strncmp(info, "BODY ", 5))
533                                        {
534                                                info += 5;
535                                                sd->body = g_list_append(sd->body, g_strdup(info));
536                                        }
537                                        else if(!strncmp(info, "TYPE ", 5))
538                                        {
539                                                info += 5;
540                                                g_free(sd->type);
541                                                sd->type = g_strdup(info);
542                                        }
543                                        else if(!strncmp(info, "CHATNAME ", 9))
544                                        {
545                                                info += 9;
546                                                if(sd->handle && sd->body && sd->type)
547                                                {
548                                                        struct groupchat *gc = skype_chat_by_name(ic, info);
549                                                        int i;
550                                                        for(i=0;i<g_list_length(sd->body);i++)
551                                                        {
552                                                                char *body = g_list_nth_data(sd->body, i);
553                                                                if(!strcmp(sd->type, "SAID") || !strcmp(sd->type, "EMOTED"))
554                                                                {
555                                                                        char *st;
556                                                                        if(!strcmp(sd->type, "SAID"))
557                                                                                st = g_strdup(body);
558                                                                        else
559                                                                        {
560                                                                                st = g_strdup_printf("/me %s", body);
561                                                                        }
562                                                                        if(!gc)
563                                                                                /* Private message */
564                                                                                imcb_buddy_msg(ic, sd->handle, st, 0, 0);
565                                                                        else
566                                                                                /* Groupchat message */
567                                                                                imcb_chat_msg(gc, sd->handle, st, 0, 0);
568                                                                        g_free(st);
569                                                                }
570                                                                else if(!strcmp(sd->type, "SETTOPIC"))
571                                                                {
572                                                                        if(gc)
573                                                                                imcb_chat_topic(gc, sd->handle, body, 0);
574                                                                }
575                                                                else if(!strcmp(sd->type, "LEFT"))
576                                                                {
577                                                                        if(gc)
578                                                                                imcb_chat_remove_buddy(gc, sd->handle, NULL);
579                                                                }
580                                                        }
581                                                        g_list_free(sd->body);
582                                                        sd->body = NULL;
583                                                }
584                                        }
585                                }
586                        }
587                        else if(!strncmp(line, "CALL ", 5))
588                        {
589                                char *id = strchr(line, ' ');
590                                if(++id)
591                                {
592                                        char *info = strchr(id, ' ');
593                                        *info = '\0';
594                                        info++;
595                                        if(!strcmp(info, "STATUS RINGING"))
596                                        {
597                                                if(sd->call_id)
598                                                        g_free(sd->call_id);
599                                                sd->call_id = g_strdup(id);
600                                                g_snprintf(buf, 1024, "GET CALL %s PARTNER_HANDLE\n", id);
601                                                skype_write( ic, buf, strlen( buf ) );
602                                                sd->call_status = SKYPE_CALL_RINGING;
603                                        }
604                                        else if(!strcmp(info, "STATUS MISSED"))
605                                        {
606                                                g_snprintf(buf, 1024, "GET CALL %s PARTNER_HANDLE\n", id);
607                                                skype_write( ic, buf, strlen( buf ) );
608                                                sd->call_status = SKYPE_CALL_MISSED;
609                                        }
610                                        else if(!strcmp(info, "STATUS CANCELLED"))
611                                        {
612                                                        g_snprintf(buf, 1024, "GET CALL %s PARTNER_HANDLE\n", id);
613                                                        skype_write( ic, buf, strlen( buf ) );
614                                                        sd->call_status = SKYPE_CALL_CANCELLED;
615                                        }
616                                        else if(!strcmp(info, "STATUS FINISHED"))
617                                        {
618                                                g_snprintf(buf, 1024, "GET CALL %s PARTNER_HANDLE\n", id);
619                                                skype_write( ic, buf, strlen( buf ) );
620                                                sd->call_status = SKYPE_CALL_FINISHED;
621                                        }
622                                        else if(!strcmp(info, "STATUS REFUSED"))
623                                        {
624                                                g_snprintf(buf, 1024, "GET CALL %s PARTNER_HANDLE\n", id);
625                                                skype_write( ic, buf, strlen( buf ) );
626                                                sd->call_status = SKYPE_CALL_REFUSED;
627                                        }
628                                        else if(!strcmp(info, "STATUS UNPLACED"))
629                                        {
630                                                if(sd->call_id)
631                                                        g_free(sd->call_id);
632                                                /* Save the ID for later usage (Cancel/Finish). */
633                                                sd->call_id = g_strdup(id);
634                                                sd->call_out = TRUE;
635                                        }
636                                        else if(!strncmp(info, "DURATION ", 9))
637                                        {
638                                                if(sd->call_duration)
639                                                        g_free(sd->call_duration);
640                                                sd->call_duration = g_strdup(info+9);
641                                        }
642                                        else if(!strncmp(info, "PARTNER_HANDLE ", 15))
643                                        {
644                                                info += 15;
645                                                if(sd->call_status) {
646                                                        switch(sd->call_status)
647                                                        {
648                                                                case SKYPE_CALL_RINGING:
649                                                                        if(sd->call_out)
650                                                                                imcb_log(ic, "You are currently ringing the user %s.", info);
651                                                                        else
652                                                                        {
653                                                                                g_snprintf(buf, 1024, "The user %s is currently ringing you.", info);
654                                                                                skype_call_ask(ic, sd->call_id, buf);
655                                                                        }
656                                                                        break;
657                                                                case SKYPE_CALL_MISSED:
658                                                                        imcb_log(ic, "You have missed a call from user %s.", info);
659                                                                        break;
660                                                                case SKYPE_CALL_CANCELLED:
661                                                                        imcb_log(ic, "You cancelled the call to the user %s.", info);
662                                                                        sd->call_status = 0;
663                                                                        sd->call_out = FALSE;
664                                                                        break;
665                                                                case SKYPE_CALL_REFUSED:
666                                                                        if(sd->call_out)
667                                                                                imcb_log(ic, "The user %s refused the call.", info);
668                                                                        else
669                                                                                imcb_log(ic, "You refused the call from user %s.", info);
670                                                                        sd->call_out = FALSE;
671                                                                        break;
672                                                                case SKYPE_CALL_FINISHED:
673                                                                        if(sd->call_duration)
674                                                                                imcb_log(ic, "You finished the call to the user %s (duration: %s seconds).", info, sd->call_duration);
675                                                                        else
676                                                                                imcb_log(ic, "You finished the call to the user %s.", info);
677                                                                        sd->call_out = FALSE;
678                                                                        break;
679                                                                default:
680                                                                        /* Don't be noisy, ignore other statuses for now. */
681                                                                        break;
682                                                        }
683                                                        sd->call_status = 0;
684                                                }
685                                        }
686                                }
687                        }
688                        else if(!strncmp(line, "FILETRANSFER ", 13))
689                        {
690                                char *id = strchr(line, ' ');
691                                if(++id)
692                                {
693                                        char *info = strchr(id, ' ');
694                                        *info = '\0';
695                                        info++;
696                                        if(!strcmp(info, "STATUS NEW"))
697                                        {
698                                                g_snprintf(buf, 1024, "GET FILETRANSFER %s PARTNER_HANDLE\n", id);
699                                                skype_write( ic, buf, strlen( buf ) );
700                                                sd->filetransfer_status = SKYPE_FILETRANSFER_NEW;
701                                        }
702                                        else if(!strcmp(info, "STATUS FAILED"))
703                                        {
704                                                g_snprintf(buf, 1024, "GET FILETRANSFER %s PARTNER_HANDLE\n", id);
705                                                skype_write( ic, buf, strlen( buf ) );
706                                                sd->filetransfer_status = SKYPE_FILETRANSFER_FAILED;
707                                        }
708                                        else if(!strncmp(info, "PARTNER_HANDLE ", 15))
709                                        {
710                                                info += 15;
711                                                if(sd->filetransfer_status) {
712                                                        switch(sd->filetransfer_status)
713                                                        {
714                                                                case SKYPE_FILETRANSFER_NEW:
715                                                                        imcb_log(ic, "The user %s offered a new file for you.", info);
716                                                                        break;
717                                                                case SKYPE_FILETRANSFER_FAILED:
718                                                                        imcb_log(ic, "Failed to transfer file from user %s.", info);
719                                                                        break;
720                                                        }
721                                                        sd->filetransfer_status = 0;
722                                                }
723                                        }
724                                }
725                        }
726                        else if(!strncmp(line, "CHAT ", 5))
727                        {
728                                char *id = strchr(line, ' ');
729                                if(++id)
730                                {
731                                        char *info = strchr(id, ' ');
732                                        if(info)
733                                                *info = '\0';
734                                        info++;
735                                        /* Remove fake chat if we created one in skype_chat_with() */
736                                        struct groupchat *gc = skype_chat_by_name(ic, "");
737                                        if(gc)
738                                                imcb_chat_free(gc);
739                                        if(!strcmp(info, "STATUS MULTI_SUBSCRIBED"))
740                                        {
741                                                imcb_chat_new( ic, id );
742                                                g_snprintf(buf, 1024, "GET CHAT %s ADDER\n", id);
743                                                skype_write(ic, buf, strlen(buf));
744                                                g_snprintf(buf, 1024, "GET CHAT %s TOPIC\n", id);
745                                                skype_write(ic, buf, strlen(buf));
746                                        }
747                                        else if(!strcmp(info, "STATUS DIALOG") && sd->groupchat_with)
748                                        {
749                                                gc = imcb_chat_new( ic, id );
750                                                /* According to the docs this
751                                                 * is necessary. However it
752                                                 * does not seem the situation
753                                                 * and it would open an extra
754                                                 * window on our client, so
755                                                 * just leave it out. */
756                                                /*g_snprintf(buf, 1024, "OPEN CHAT %s\n", id);
757                                                skype_write(ic, buf, strlen(buf));*/
758                                                g_snprintf(buf, 1024, "%s@skype.com", sd->groupchat_with);
759                                                imcb_chat_add_buddy(gc, buf);
760                                                imcb_chat_add_buddy(gc, sd->username);
761                                                g_free(sd->groupchat_with);
762                                                sd->groupchat_with = NULL;
763                                                g_snprintf(buf, 1024, "GET CHAT %s ADDER\n", id);
764                                                skype_write(ic, buf, strlen(buf));
765                                                g_snprintf(buf, 1024, "GET CHAT %s TOPIC\n", id);
766                                                skype_write(ic, buf, strlen(buf));
767                                        }
768                                        else if(!strcmp(info, "STATUS UNSUBSCRIBED"))
769                                        {
770                                                gc = skype_chat_by_name(ic, id);
771                                                if(gc)
772                                                        gc->data = (void*)FALSE;
773                                        }
774                                        else if(!strncmp(info, "ADDER ", 6))
775                                        {
776                                                info += 6;
777                                                g_free(sd->adder);
778                                                sd->adder = g_strdup_printf("%s@skype.com", info);
779                                        }
780                                        else if(!strncmp(info, "TOPIC ", 6))
781                                        {
782                                                info += 6;
783                                                gc = skype_chat_by_name(ic, id);
784                                                if(gc && (sd->adder || sd->topic_wait))
785                                                {
786                                                        if(sd->topic_wait)
787                                                        {
788                                                                sd->adder = g_strdup(sd->username);
789                                                                sd->topic_wait = 0;
790                                                        }
791                                                        imcb_chat_topic(gc, sd->adder, info, 0);
792                                                        g_free(sd->adder);
793                                                        sd->adder = NULL;
794                                                }
795                                        }
796                                        else if(!strncmp(info, "ACTIVEMEMBERS ", 14))
797                                        {
798                                                info += 14;
799                                                gc = skype_chat_by_name(ic, id);
800                                                /* Hack! We set ->data to TRUE
801                                                 * while we're on the channel
802                                                 * so that we won't rejoin
803                                                 * after a /part. */
804                                                if(gc && !gc->data)
805                                                {
806                                                        char **members = g_strsplit(info, " ", 0);
807                                                        int i;
808                                                        for(i=0;members[i];i++)
809                                                        {
810                                                                if(!strcmp(members[i], sd->username))
811                                                                        continue;
812                                                                g_snprintf(buf, 1024, "%s@skype.com", members[i]);
813                                                                if(!g_list_find_custom(gc->in_room, buf, (GCompareFunc)strcmp))
814                                                                        imcb_chat_add_buddy(gc, buf);
815                                                        }
816                                                        imcb_chat_add_buddy(gc, sd->username);
817                                                        g_strfreev(members);
818                                                }
819                                        }
820                                }
821                        }
822                        else if(!strncmp(line, "PASSWORD ", 9))
823                        {
824                                if(!strncmp(line+9, "OK", 2))
825                                        imcb_connected(ic);
826                                else
827                                {
828                                        imcb_error(ic, "Authentication Failed");
829                                        imc_logout( ic, TRUE );
830                                }
831                        }
832                        lineptr++;
833                }
834                g_strfreev(lines);
835        }
836        else if( st == 0 || ( st < 0 && !sockerr_again() ) )
837        {
838                closesocket( sd->fd );
839                sd->fd = -1;
840
841                imcb_error( ic, "Error while reading from server" );
842                imc_logout( ic, TRUE );
843                return FALSE;
844        }
845        return TRUE;
846}
847
848gboolean skype_start_stream( struct im_connection *ic )
849{
850        struct skype_data *sd = ic->proto_data;
851        char *buf;
852        int st;
853
854        if(!sd)
855                return FALSE;
856
857        if( sd->bfd <= 0 )
858                sd->bfd = b_input_add( sd->fd, GAIM_INPUT_READ, skype_read_callback, ic );
859
860        /* Log in */
861        buf = g_strdup_printf("USERNAME %s\n", ic->acc->user);
862        st = skype_write( ic, buf, strlen( buf ) );
863        g_free(buf);
864        buf = g_strdup_printf("PASSWORD %s\n", ic->acc->pass);
865        st = skype_write( ic, buf, strlen( buf ) );
866        g_free(buf);
867
868        /* This will download all buddies. */
869        buf = g_strdup_printf("SEARCH FRIENDS\n");
870        st = skype_write( ic, buf, strlen( buf ) );
871        g_free(buf);
872        buf = g_strdup_printf("SET USERSTATUS ONLINE\n");
873        skype_write( ic, buf, strlen( buf ) );
874        g_free(buf);
875        return st;
876}
877
878gboolean skype_connected( gpointer data, void *source, b_input_condition cond )
879{
880        struct im_connection *ic = data;
881        struct skype_data *sd = ic->proto_data;
882        if(!source)
883        {
884                sd->ssl = NULL;
885                imcb_error( ic, "Could not connect to server" );
886                imc_logout( ic, TRUE );
887                return FALSE;
888        }
889        imcb_log( ic, "Connected to server, logging in" );
890        return skype_start_stream(ic);
891}
892
893static void skype_login( account_t *acc )
894{
895        struct im_connection *ic = imcb_new( acc );
896        struct skype_data *sd = g_new0( struct skype_data, 1 );
897
898        ic->proto_data = sd;
899
900        imcb_log( ic, "Connecting" );
901        sd->ssl = ssl_connect(set_getstr( &acc->set, "server" ), set_getint( &acc->set, "port" ), skype_connected, ic );
902        sd->fd = sd->ssl ? ssl_getfd( sd->ssl ) : -1;
903        sd->username = g_strdup( acc->user );
904
905        sd->ic = ic;
906}
907
908static void skype_logout( struct im_connection *ic )
909{
910        struct skype_data *sd = ic->proto_data;
911        char *buf;
912
913        buf = g_strdup_printf("SET USERSTATUS OFFLINE\n");
914        skype_write( ic, buf, strlen( buf ) );
915        g_free(buf);
916
917        g_free(sd->username);
918        g_free(sd->handle);
919        g_free(sd);
920        ic->proto_data = NULL;
921}
922
923static int skype_buddy_msg( struct im_connection *ic, char *who, char *message, int flags )
924{
925        char *buf, *ptr, *nick;
926        int st;
927
928        nick = g_strdup(who);
929        ptr = strchr(nick, '@');
930        if(ptr)
931                *ptr = '\0';
932
933        buf = g_strdup_printf("MESSAGE %s %s\n", nick, message);
934        g_free(nick);
935        st = skype_write( ic, buf, strlen( buf ) );
936        g_free(buf);
937
938        return st;
939}
940
941const struct skype_away_state *skype_away_state_by_name( char *name )
942{
943        int i;
944
945        for( i = 0; skype_away_state_list[i].full_name; i ++ )
946                if( g_strcasecmp( skype_away_state_list[i].full_name, name ) == 0 )
947                        return( skype_away_state_list + i );
948
949        return NULL;
950}
951
952static void skype_set_away( struct im_connection *ic, char *state_txt, char *message )
953{
954        const struct skype_away_state *state;
955        char *buf;
956
957        if( strcmp( state_txt, GAIM_AWAY_CUSTOM ) == 0 )
958                state = skype_away_state_by_name( "Away" );
959        else
960                state = skype_away_state_by_name( state_txt );
961        buf = g_strdup_printf("SET USERSTATUS %s\n", state->code);
962        skype_write( ic, buf, strlen( buf ) );
963        g_free(buf);
964}
965
966static GList *skype_away_states( struct im_connection *ic )
967{
968        static GList *l = NULL;
969        int i;
970       
971        if( l == NULL )
972                for( i = 0; skype_away_state_list[i].full_name; i ++ )
973                        l = g_list_append( l, (void*) skype_away_state_list[i].full_name );
974       
975        return l;
976}
977
978static char *skype_set_display_name( set_t *set, char *value )
979{
980        account_t *acc = set->data;
981        struct im_connection *ic = acc->ic;
982        char *buf;
983
984        buf = g_strdup_printf("SET PROFILE FULLNAME %s", value);
985        skype_write( ic, buf, strlen( buf ) );
986        g_free(buf);
987        return(value);
988}
989
990static char *skype_set_call( set_t *set, char *value )
991{
992        account_t *acc = set->data;
993        struct im_connection *ic = acc->ic;
994        struct skype_data *sd = ic->proto_data;
995        char *nick, *ptr, *buf;
996
997        if(value)
998        {
999                user_t *u = user_find(acc->irc, value);
1000                /* We are starting a call */
1001                if(!u && strcmp(value, "echo123"))
1002                {
1003                        imcb_error(ic, "%s - no such nick", value);
1004                        return(value);
1005                }
1006                if(!strcmp(value, "echo123"))
1007                        nick = g_strdup("echo123");
1008                else
1009                        nick = g_strdup(u->handle);
1010                ptr = strchr(nick, '@');
1011                if(ptr)
1012                        *ptr = '\0';
1013
1014                buf = g_strdup_printf("CALL %s", nick);
1015                skype_write( ic, buf, strlen( buf ) );
1016                g_free(buf);
1017                g_free(nick);
1018        }
1019        else
1020        {
1021                /* We are ending a call */
1022                if(sd->call_id)
1023                {
1024                        buf = g_strdup_printf("SET CALL %s STATUS FINISHED", sd->call_id);
1025                        skype_write( ic, buf, strlen( buf ) );
1026                        g_free(buf);
1027                        g_free(sd->call_id);
1028                        sd->call_id = NULL;
1029                }
1030                else
1031                {
1032                        imcb_error(ic, "There are no active calls currently.");
1033                }
1034        }
1035        return(value);
1036}
1037
1038static void skype_add_buddy( struct im_connection *ic, char *who, char *group )
1039{
1040        char *buf, *nick, *ptr;
1041
1042        nick = g_strdup(who);
1043        ptr = strchr(nick, '@');
1044        if(ptr)
1045                *ptr = '\0';
1046        buf = g_strdup_printf("SET USER %s BUDDYSTATUS 2 Please authorize me\n", nick);
1047        skype_write( ic, buf, strlen( buf ) );
1048        g_free(nick);
1049}
1050
1051static void skype_remove_buddy( struct im_connection *ic, char *who, char *group )
1052{
1053        char *buf, *nick, *ptr;
1054
1055        nick = g_strdup(who);
1056        ptr = strchr(nick, '@');
1057        if(ptr)
1058                *ptr = '\0';
1059        buf = g_strdup_printf("SET USER %s BUDDYSTATUS 1\n", nick);
1060        skype_write( ic, buf, strlen( buf ) );
1061        g_free(nick);
1062}
1063
1064void skype_chat_msg( struct groupchat *gc, char *message, int flags )
1065{
1066        struct im_connection *ic = gc->ic;
1067        char *buf;
1068        buf = g_strdup_printf("CHATMESSAGE %s %s\n", gc->title, message);
1069        skype_write( ic, buf, strlen( buf ) );
1070        g_free(buf);
1071}
1072
1073void skype_chat_leave( struct groupchat *gc )
1074{
1075        struct im_connection *ic = gc->ic;
1076        char *buf;
1077        buf = g_strdup_printf("ALTER CHAT %s LEAVE\n", gc->title);
1078        skype_write( ic, buf, strlen( buf ) );
1079        g_free(buf);
1080        gc->data = (void*)TRUE;
1081}
1082
1083void skype_chat_invite(struct groupchat *gc, char *who, char *message)
1084{
1085        struct im_connection *ic = gc->ic;
1086        char *buf, *ptr, *nick;
1087        nick = g_strdup(message);
1088        ptr = strchr(nick, '@');
1089        if(ptr)
1090                *ptr = '\0';
1091        buf = g_strdup_printf("ALTER CHAT %s ADDMEMBERS %s\n", gc->title, nick);
1092        skype_write( ic, buf, strlen( buf ) );
1093        g_free(buf);
1094        g_free(nick);
1095}
1096
1097void skype_chat_topic(struct groupchat *gc, char *message)
1098{
1099        struct im_connection *ic = gc->ic;
1100        struct skype_data *sd = ic->proto_data;
1101        char *buf;
1102        buf = g_strdup_printf("ALTER CHAT %s SETTOPIC %s\n", gc->title, message);
1103        skype_write( ic, buf, strlen( buf ) );
1104        g_free(buf);
1105        sd->topic_wait = 1;
1106}
1107
1108struct groupchat *skype_chat_with(struct im_connection *ic, char *who)
1109{
1110        struct skype_data *sd = ic->proto_data;
1111        char *ptr, *nick, *buf;
1112        nick = g_strdup(who);
1113        ptr = strchr(nick, '@');
1114        if(ptr)
1115                *ptr = '\0';
1116        buf = g_strdup_printf("CHAT CREATE %s\n", nick);
1117        skype_write(ic, buf, strlen(buf));
1118        g_free(buf);
1119        sd->groupchat_with = g_strdup(nick);
1120        g_free(nick);
1121        /* We create a fake chat for now. We will replace it with a real one in
1122         * the real callback. */
1123        return(imcb_chat_new( ic, "" ));
1124}
1125
1126static void skype_get_info(struct im_connection *ic, char *who)
1127{
1128        char *ptr, *nick, *buf;
1129        nick = g_strdup(who);
1130        ptr = strchr(nick, '@');
1131        if(ptr)
1132                *ptr = '\0';
1133        buf = g_strdup_printf("GET USER %s FULLNAME\n", nick);
1134        skype_write(ic, buf, strlen(buf));
1135        g_free(buf);
1136        buf = g_strdup_printf("GET USER %s PHONE_HOME\n", nick);
1137        skype_write(ic, buf, strlen(buf));
1138        g_free(buf);
1139        buf = g_strdup_printf("GET USER %s PHONE_OFFICE\n", nick);
1140        skype_write(ic, buf, strlen(buf));
1141        g_free(buf);
1142        buf = g_strdup_printf("GET USER %s PHONE_MOBILE\n", nick);
1143        skype_write(ic, buf, strlen(buf));
1144        g_free(buf);
1145        buf = g_strdup_printf("GET USER %s NROF_AUTHED_BUDDIES\n", nick);
1146        skype_write(ic, buf, strlen(buf));
1147        g_free(buf);
1148        buf = g_strdup_printf("GET USER %s TIMEZONE\n", nick);
1149        skype_write(ic, buf, strlen(buf));
1150        g_free(buf);
1151        buf = g_strdup_printf("GET USER %s LASTONLINETIMESTAMP\n", nick);
1152        skype_write(ic, buf, strlen(buf));
1153        g_free(buf);
1154        buf = g_strdup_printf("GET USER %s BIRTHDAY\n", nick);
1155        skype_write(ic, buf, strlen(buf));
1156        g_free(buf);
1157        buf = g_strdup_printf("GET USER %s SEX\n", nick);
1158        skype_write(ic, buf, strlen(buf));
1159        g_free(buf);
1160        buf = g_strdup_printf("GET USER %s LANGUAGE\n", nick);
1161        skype_write(ic, buf, strlen(buf));
1162        g_free(buf);
1163        buf = g_strdup_printf("GET USER %s COUNTRY\n", nick);
1164        skype_write(ic, buf, strlen(buf));
1165        g_free(buf);
1166        buf = g_strdup_printf("GET USER %s PROVINCE\n", nick);
1167        skype_write(ic, buf, strlen(buf));
1168        g_free(buf);
1169        buf = g_strdup_printf("GET USER %s CITY\n", nick);
1170        skype_write(ic, buf, strlen(buf));
1171        g_free(buf);
1172        buf = g_strdup_printf("GET USER %s HOMEPAGE\n", nick);
1173        skype_write(ic, buf, strlen(buf));
1174        g_free(buf);
1175        buf = g_strdup_printf("GET USER %s ABOUT\n", nick);
1176        skype_write(ic, buf, strlen(buf));
1177        g_free(buf);
1178}
1179
1180static void skype_set_my_name( struct im_connection *ic, char *info )
1181{
1182        skype_set_display_name( set_find( &ic->acc->set, "display_name" ), info );
1183}
1184
1185static void skype_init( account_t *acc )
1186{
1187        set_t *s;
1188
1189        s = set_add( &acc->set, "server", SKYPE_DEFAULT_SERVER, set_eval_account, acc );
1190        s->flags |= ACC_SET_OFFLINE_ONLY;
1191
1192        s = set_add( &acc->set, "port", SKYPE_DEFAULT_PORT, set_eval_int, acc );
1193        s->flags |= ACC_SET_OFFLINE_ONLY;
1194
1195        s = set_add( &acc->set, "display_name", NULL, skype_set_display_name, acc );
1196        s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY;
1197
1198        s = set_add( &acc->set, "call", NULL, skype_set_call, acc );
1199        s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY;
1200}
1201
1202void init_plugin(void)
1203{
1204        struct prpl *ret = g_new0( struct prpl, 1 );
1205
1206        ret->name = "skype";
1207        ret->login = skype_login;
1208        ret->init = skype_init;
1209        ret->logout = skype_logout;
1210        ret->buddy_msg = skype_buddy_msg;
1211        ret->get_info = skype_get_info;
1212        ret->set_my_name = skype_set_my_name;
1213        ret->away_states = skype_away_states;
1214        ret->set_away = skype_set_away;
1215        ret->add_buddy = skype_add_buddy;
1216        ret->remove_buddy = skype_remove_buddy;
1217        ret->chat_msg = skype_chat_msg;
1218        ret->chat_leave = skype_chat_leave;
1219        ret->chat_invite = skype_chat_invite;
1220        ret->chat_with = skype_chat_with;
1221        ret->handle_cmp = g_strcasecmp;
1222        ret->chat_topic = skype_chat_topic;
1223        register_protocol( ret );
1224}
1225
1226/* vim: set ts=2 sw=2 noet: */
Note: See TracBrowser for help on using the repository browser.