source: skype/skype.c @ 93052e1

Last change on this file since 93052e1 was 93052e1, checked in by Miklos Vajna <vmiklos@…>, at 2007-12-16T02:55:56Z

added much more info output, need to finetune format

  • Property mode set to 100644
File size: 26.1 KB
Line 
1/*
2 *  skype.c - Skype plugin for BitlBee
3 *
4 *  Copyright (c) 2007 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#include <stdio.h>
27#include <poll.h>
28#include <bitlbee.h>
29#include <glib.h>
30
31#define SKYPE_PORT_DEFAULT "2727"
32
33/*
34 * Enumerations
35 */
36
37typedef enum
38{
39        SKYPE_CALL_RINGING = 1,
40        SKYPE_CALL_MISSED
41} skype_call_status;
42
43typedef enum
44{
45        SKYPE_FILETRANSFER_NEW = 1,
46        SKYPE_FILETRANSFER_FAILED
47} skype_filetransfer_status;
48
49/*
50 * Structures
51 */
52
53struct skype_data
54{
55        struct im_connection *ic;
56        char *username;
57        /* The effective file descriptor. We store it here so any function can
58         * write() to it. */
59        int fd;
60        /* File descriptor returned by bitlbee. we store it so we know when
61         * we're connected and when we aren't. */
62        int bfd;
63        /* When we receive a new message id, we query the properties, finally
64         * the chatname. Store the properties here so that we can use
65         * imcb_buddy_msg() when we got the chatname. */
66        char *handle;
67        /* List, because of multiline messages. */
68        GList *body;
69        char *type;
70        /* This is necessary because we send a notification when we get the
71         * handle. So we store the state here and then we can send a
72         * notification about the handle is in a given status. */
73        skype_call_status call_status;
74        /* Same for file transfers. */
75        skype_filetransfer_status filetransfer_status;
76        /* Using /j #nick we want to have a groupchat with two people. Usually
77         * not (default). */
78        char* groupchat_with;
79        /* The user who invited us to the chat. */
80        char* adder;
81        /* If we are waiting for a confirmation about we changed the topic. */
82        int topic_wait;
83        /* These are used by the info command. */
84        char *info_fullname;
85        char *info_phonehome;
86        char *info_phoneoffice;
87        char *info_phonemobile;
88        char *info_nrbuddies;
89        char *info_tz;
90        char *info_seen;
91        char *info_birthday;
92        char *info_sex;
93        char *info_language;
94        char *info_country;
95        char *info_province;
96        char *info_city;
97        char *info_homepage;
98        char *info_about;
99};
100
101struct skype_away_state
102{
103        char *code;
104        char *full_name;
105};
106
107struct skype_buddy_ask_data
108{
109        struct im_connection *ic;
110        char *handle;
111};
112
113/*
114 * Tables
115 */
116
117const struct skype_away_state skype_away_state_list[] =
118{
119        { "ONLINE",  "Online" },
120        { "SKYPEME",  "Skype Me" },
121        { "AWAY",   "Away" },
122        { "NA",    "Not available" },
123        { "DND",      "Do Not Disturb" },
124        { "INVISIBLE",      "Invisible" },
125        { "OFFLINE",      "Offline" },
126        { NULL, NULL}
127};
128
129/*
130 * Functions
131 */
132
133static void skype_init( account_t *acc )
134{
135        set_t *s;
136
137        s = set_add( &acc->set, "port", SKYPE_PORT_DEFAULT, set_eval_int, acc );
138        s->flags |= ACC_SET_OFFLINE_ONLY;
139
140        s = set_add( &acc->set, "server", NULL, set_eval_account, acc );
141        s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
142}
143
144int skype_write( struct im_connection *ic, char *buf, int len )
145{
146        struct skype_data *sd = ic->proto_data;
147        struct pollfd pfd[1];
148
149        pfd[0].fd = sd->fd;
150        pfd[0].events = POLLOUT;
151
152        /* This poll is necessary or we'll get a SIGPIPE when we write() to
153         * sd->fd. */
154        poll(pfd, 1, 1000);
155        if(pfd[0].revents & POLLHUP)
156        {
157                imcb_error( ic, "Could not connect to server" );
158                imc_logout( ic, TRUE );
159                return FALSE;
160        }
161        write( sd->fd, buf, len );
162
163        return TRUE;
164}
165
166static void skype_buddy_ask_yes( gpointer w, struct skype_buddy_ask_data *bla )
167{
168        char *buf = g_strdup_printf("SET USER %s ISAUTHORIZED TRUE", bla->handle);
169        skype_write( bla->ic, buf, strlen( buf ) );
170        g_free(buf);
171        g_free(bla->handle);
172        g_free(bla);
173}
174
175static void skype_buddy_ask_no( gpointer w, struct skype_buddy_ask_data *bla )
176{
177        char *buf = g_strdup_printf("SET USER %s ISAUTHORIZED FALSE", bla->handle);
178        skype_write( bla->ic, buf, strlen( buf ) );
179        g_free(buf);
180        g_free(bla->handle);
181        g_free(bla);
182}
183
184void skype_buddy_ask( struct im_connection *ic, char *handle, char *message)
185{
186        struct skype_buddy_ask_data *bla = g_new0( struct skype_buddy_ask_data, 1 );
187        char *buf;
188
189        bla->ic = ic;
190        bla->handle = g_strdup(handle);
191
192        buf = g_strdup_printf( "The user %s wants to add you to his/her buddy list, saying: '%s'.", handle, message);
193        imcb_ask( ic, buf, bla, skype_buddy_ask_yes, skype_buddy_ask_no );
194        g_free( buf );
195}
196
197struct groupchat *skype_chat_by_name( struct im_connection *ic, char *name )
198{
199        struct groupchat *ret;
200
201        for( ret = ic->groupchats; ret; ret = ret->next )
202        {
203                if(strcmp(name, ret->title ) == 0 )
204                        break;
205        }
206
207        return ret;
208}
209
210static gboolean skype_read_callback( gpointer data, gint fd, b_input_condition cond )
211{
212        struct im_connection *ic = data;
213        struct skype_data *sd = ic->proto_data;
214        char buf[1024];
215        int st;
216        char **lines, **lineptr, *line, *ptr;
217
218        if( !sd || sd->fd == -1 )
219                return FALSE;
220        /* Read the whole data. */
221        st = read( sd->fd, buf, sizeof( buf ) );
222        if( st > 0 )
223        {
224                buf[st] = '\0';
225                /* Then split it up to lines. */
226                lines = g_strsplit(buf, "\n", 0);
227                lineptr = lines;
228                while((line = *lineptr))
229                {
230                        if(!strlen(line))
231                                break;
232                        if(!strncmp(line, "USERS ", 6))
233                        {
234                                char **i;
235                                char **nicks;
236
237                                nicks = g_strsplit(line + 6, ", ", 0);
238                                i = nicks;
239                                while(*i)
240                                {
241                                        g_snprintf(buf, 1024, "GET USER %s ONLINESTATUS\n", *i);
242                                        skype_write( ic, buf, strlen( buf ) );
243                                        i++;
244                                }
245                                g_strfreev(nicks);
246                        }
247                        else if(!strncmp(line, "USER ", 5))
248                        {
249                                int flags = 0;
250                                char *status = strrchr(line, ' ');
251                                char *user = strchr(line, ' ');
252                                status++;
253                                ptr = strchr(++user, ' ');
254                                *ptr = '\0';
255                                ptr++;
256                                if(!strncmp(ptr, "ONLINESTATUS ", 13) &&
257                                                strcmp(user, sd->username) != 0
258                                                && strcmp(user, "echo123") != 0)
259                                {
260                                        ptr = g_strdup_printf("%s@skype.com", user);
261                                        imcb_add_buddy(ic, ptr, NULL);
262                                        if(strcmp(status, "OFFLINE") != 0)
263                                                flags |= OPT_LOGGED_IN;
264                                        if(strcmp(status, "ONLINE") != 0 && strcmp(status, "SKYPEME") != 0)
265                                                flags |= OPT_AWAY;
266                                        imcb_buddy_status(ic, ptr, flags, NULL, NULL);
267                                        g_free(ptr);
268                                }
269                                else if(!strncmp(ptr, "RECEIVEDAUTHREQUEST ", 20))
270                                {
271                                        char *message = ptr + 20;
272                                        if(strlen(message))
273                                                skype_buddy_ask(ic, user, message);
274                                }
275                                else if(!strncmp(ptr, "BUDDYSTATUS ", 12))
276                                {
277                                        char *st = ptr + 12;
278                                        if(!strcmp(st, "3"))
279                                        {
280                                                char *buf = g_strdup_printf("%s@skype.com", user);
281                                                imcb_add_buddy(ic, buf, NULL);
282                                                g_free(buf);
283                                        }
284                                }
285                                else if(!strncmp(ptr, "FULLNAME ", 9))
286                                        sd->info_fullname = g_strdup_printf("%s", ptr + 9);
287                                else if(!strncmp(ptr, "PHONE_HOME ", 11))
288                                        sd->info_phonehome = g_strdup_printf("%s", ptr + 11);
289                                else if(!strncmp(ptr, "PHONE_OFFICE ", 13))
290                                        sd->info_phoneoffice = g_strdup_printf("%s", ptr + 13);
291                                else if(!strncmp(ptr, "PHONE_MOBILE ", 13))
292                                        sd->info_phonemobile = g_strdup_printf("%s", ptr + 13);
293                                else if(!strncmp(ptr, "NROF_AUTHED_BUDDIES ", 20))
294                                        sd->info_nrbuddies = g_strdup_printf("%s", ptr + 20);
295                                else if(!strncmp(ptr, "TIMEZONE ", 9))
296                                        sd->info_tz = g_strdup_printf("%s", ptr + 9);
297                                else if(!strncmp(ptr, "LASTONLINETIMESTAMP ", 20))
298                                        sd->info_seen = g_strdup_printf("%s", ptr + 20);
299                                else if(!strncmp(ptr, "BIRTHDAY ", 9))
300                                        sd->info_birthday = g_strdup_printf("%s", ptr + 9);
301                                else if(!strncmp(ptr, "SEX ", 4))
302                                        sd->info_sex = g_strdup_printf("%s", ptr + 4);
303                                else if(!strncmp(ptr, "LANGUAGE ", 9))
304                                        sd->info_language = g_strdup_printf("%s", ptr + 9);
305                                else if(!strncmp(ptr, "COUNTRY ", 8))
306                                        sd->info_country = g_strdup_printf("%s", ptr + 8);
307                                else if(!strncmp(ptr, "PROVINCE ", 9))
308                                        sd->info_province = g_strdup_printf("%s", ptr + 9);
309                                else if(!strncmp(ptr, "CITY ", 5))
310                                        sd->info_city = g_strdup_printf("%s", ptr + 5);
311                                else if(!strncmp(ptr, "HOMEPAGE ", 9))
312                                        sd->info_homepage = g_strdup_printf("%s", ptr + 9);
313                                else if(!strncmp(ptr, "ABOUT ", 6))
314                                {
315                                        sd->info_about = g_strdup_printf("%s", ptr + 6);
316
317                                        GString *st = g_string_new("Contact Information\n");
318                                        g_string_append_printf(st, "Skype Name: %s\n", user);
319                                        if(sd->info_fullname)
320                                        {
321                                                if(strlen(sd->info_fullname))
322                                                        g_string_append_printf(st, "Full Name: %s\n", sd->info_fullname);
323                                                g_free(sd->info_fullname);
324                                        }
325                                        if(sd->info_phonehome)
326                                        {
327                                                if(strlen(sd->info_phonehome))
328                                                        g_string_append_printf(st, "Home Phone: %s\n", sd->info_phonehome);
329                                                g_free(sd->info_phonehome);
330                                        }
331                                        if(sd->info_phoneoffice)
332                                        {
333                                                if(strlen(sd->info_phoneoffice))
334                                                        g_string_append_printf(st, "Office Phone: %s\n", sd->info_phoneoffice);
335                                                g_free(sd->info_phoneoffice);
336                                        }
337                                        if(sd->info_phonemobile)
338                                        {
339                                                if(strlen(sd->info_phonemobile))
340                                                        g_string_append_printf(st, "Mobile Phone: %s\n", sd->info_phonemobile);
341                                                g_free(sd->info_phonemobile);
342                                        }
343                                        g_string_append_printf(st, "Personal Information\n");
344                                        if(sd->info_nrbuddies)
345                                        {
346                                                if(strlen(sd->info_nrbuddies))
347                                                        g_string_append_printf(st, "Contacts: %s\n", sd->info_nrbuddies);
348                                                g_free(sd->info_nrbuddies);
349                                        }
350                                        if(sd->info_tz)
351                                        {
352                                                if(strlen(sd->info_tz))
353                                                        g_string_append_printf(st, "Local Time: %s\n", sd->info_tz);
354                                                g_free(sd->info_tz);
355                                        }
356                                        if(sd->info_seen)
357                                        {
358                                                if(strlen(sd->info_seen))
359                                                        g_string_append_printf(st, "Last Seen: %s\n", sd->info_seen);
360                                                g_free(sd->info_seen);
361                                        }
362                                        if(sd->info_birthday)
363                                        {
364                                                if(strlen(sd->info_birthday))
365                                                        g_string_append_printf(st, "Birthday: %s\n", sd->info_birthday);
366                                                g_free(sd->info_birthday);
367                                        }
368                                        if(sd->info_sex)
369                                        {
370                                                if(strlen(sd->info_sex))
371                                                        g_string_append_printf(st, "Gender: %s\n", sd->info_sex);
372                                                g_free(sd->info_sex);
373                                        }
374                                        if(sd->info_language)
375                                        {
376                                                if(strlen(sd->info_language))
377                                                        g_string_append_printf(st, "Language: %s\n", sd->info_language);
378                                                g_free(sd->info_language);
379                                        }
380                                        if(sd->info_country)
381                                        {
382                                                if(strlen(sd->info_country))
383                                                        g_string_append_printf(st, "Country: %s\n", sd->info_country);
384                                                g_free(sd->info_country);
385                                        }
386                                        if(sd->info_province)
387                                        {
388                                                if(strlen(sd->info_province))
389                                                        g_string_append_printf(st, "Region: %s\n", sd->info_province);
390                                                g_free(sd->info_province);
391                                        }
392                                        if(sd->info_city)
393                                        {
394                                                if(strlen(sd->info_city))
395                                                        g_string_append_printf(st, "City: %s\n", sd->info_city);
396                                                g_free(sd->info_city);
397                                        }
398                                        if(sd->info_homepage)
399                                        {
400                                                if(strlen(sd->info_homepage))
401                                                        g_string_append_printf(st, "Homepage: %s\n", sd->info_homepage);
402                                                g_free(sd->info_homepage);
403                                        }
404                                        if(sd->info_about)
405                                        {
406                                                if(strlen(sd->info_about))
407                                                        g_string_append_printf(st, "%s\n", sd->info_about);
408                                                g_free(sd->info_about);
409                                        }
410                                        imcb_log(ic, "%s", st->str);
411                                        g_string_free(st, TRUE);
412                                }
413                        }
414                        else if(!strncmp(line, "CHATMESSAGE ", 12))
415                        {
416                                char *id = strchr(line, ' ');
417                                if(++id)
418                                {
419                                        char *info = strchr(id, ' ');
420                                        *info = '\0';
421                                        info++;
422                                        if(!strcmp(info, "STATUS RECEIVED"))
423                                        {
424                                                /* New message ID:
425                                                 * (1) Request its from field
426                                                 * (2) Request its body
427                                                 * (3) Request its type
428                                                 * (4) Query chatname
429                                                 */
430                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s FROM_HANDLE\n", id);
431                                                skype_write( ic, buf, strlen( buf ) );
432                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s BODY\n", id);
433                                                skype_write( ic, buf, strlen( buf ) );
434                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s TYPE\n", id);
435                                                skype_write( ic, buf, strlen( buf ) );
436                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s CHATNAME\n", id);
437                                                skype_write( ic, buf, strlen( buf ) );
438                                        }
439                                        else if(!strncmp(info, "FROM_HANDLE ", 12))
440                                        {
441                                                info += 12;
442                                                /* New from field value. Store
443                                                 * it, then we can later use it
444                                                 * when we got the message's
445                                                 * body. */
446                                                g_free(sd->handle);
447                                                sd->handle = g_strdup_printf("%s@skype.com", info);
448                                        }
449                                        else if(!strncmp(info, "EDITED_BY ", 10))
450                                        {
451                                                info += 10;
452                                                /* This is the same as
453                                                 * FROM_HANDLE, except that we
454                                                 * never request these lines
455                                                 * from Skype, we just get
456                                                 * them. */
457                                                g_free(sd->handle);
458                                                sd->handle = g_strdup_printf("%s@skype.com", info);
459                                        }
460                                        else if(!strncmp(info, "BODY ", 5))
461                                        {
462                                                info += 5;
463                                                sd->body = g_list_append(sd->body, g_strdup(info));
464                                        }
465                                        else if(!strncmp(info, "TYPE ", 5))
466                                        {
467                                                info += 5;
468                                                g_free(sd->type);
469                                                sd->type = g_strdup(info);
470                                        }
471                                        else if(!strncmp(info, "CHATNAME ", 9))
472                                        {
473                                                info += 9;
474                                                if(sd->handle && sd->body && sd->type)
475                                                {
476                                                        struct groupchat *gc = skype_chat_by_name(ic, info);
477                                                        int i;
478                                                        for(i=0;i<g_list_length(sd->body);i++)
479                                                        {
480                                                                char *body = g_list_nth_data(sd->body, i);
481                                                                if(!strcmp(sd->type, "SAID"))
482                                                                {
483                                                                        if(!gc)
484                                                                                /* Private message */
485                                                                                imcb_buddy_msg(ic, sd->handle, body, 0, 0);
486                                                                        else
487                                                                                /* Groupchat message */
488                                                                                imcb_chat_msg(gc, sd->handle, body, 0, 0);
489                                                                }
490                                                                else if(!strcmp(sd->type, "SETTOPIC"))
491                                                                {
492                                                                        if(gc)
493                                                                                imcb_chat_topic(gc, sd->handle, body, 0);
494                                                                }
495                                                                else if(!strcmp(sd->type, "LEFT"))
496                                                                {
497                                                                        if(gc)
498                                                                                imcb_chat_remove_buddy(gc, sd->handle, NULL);
499                                                                }
500                                                        }
501                                                        g_list_free(sd->body);
502                                                        sd->body = NULL;
503                                                }
504                                        }
505                                }
506                        }
507                        else if(!strncmp(line, "CALL ", 5))
508                        {
509                                char *id = strchr(line, ' ');
510                                if(++id)
511                                {
512                                        char *info = strchr(id, ' ');
513                                        *info = '\0';
514                                        info++;
515                                        if(!strcmp(info, "STATUS RINGING"))
516                                        {
517                                                g_snprintf(buf, 1024, "GET CALL %s PARTNER_HANDLE\n", id);
518                                                skype_write( ic, buf, strlen( buf ) );
519                                                sd->call_status = SKYPE_CALL_RINGING;
520                                        }
521                                        else if(!strcmp(info, "STATUS MISSED"))
522                                        {
523                                                g_snprintf(buf, 1024, "GET CALL %s PARTNER_HANDLE\n", id);
524                                                skype_write( ic, buf, strlen( buf ) );
525                                                sd->call_status = SKYPE_CALL_MISSED;
526                                        }
527                                        else if(!strncmp(info, "PARTNER_HANDLE ", 15))
528                                        {
529                                                info += 15;
530                                                if(sd->call_status) {
531                                                        switch(sd->call_status)
532                                                        {
533                                                                case SKYPE_CALL_RINGING:
534                                                                        imcb_log(ic, "The user %s is currently ringing you.", info);
535                                                                        break;
536                                                                case SKYPE_CALL_MISSED:
537                                                                        imcb_log(ic, "You have missed a call from user %s.", info);
538                                                                        break;
539                                                        }
540                                                        sd->call_status = 0;
541                                                }
542                                        }
543                                }
544                        }
545                        else if(!strncmp(line, "FILETRANSFER ", 13))
546                        {
547                                char *id = strchr(line, ' ');
548                                if(++id)
549                                {
550                                        char *info = strchr(id, ' ');
551                                        *info = '\0';
552                                        info++;
553                                        if(!strcmp(info, "STATUS NEW"))
554                                        {
555                                                g_snprintf(buf, 1024, "GET FILETRANSFER %s PARTNER_HANDLE\n", id);
556                                                skype_write( ic, buf, strlen( buf ) );
557                                                sd->filetransfer_status = SKYPE_FILETRANSFER_NEW;
558                                        }
559                                        else if(!strcmp(info, "STATUS FAILED"))
560                                        {
561                                                g_snprintf(buf, 1024, "GET FILETRANSFER %s PARTNER_HANDLE\n", id);
562                                                skype_write( ic, buf, strlen( buf ) );
563                                                sd->filetransfer_status = SKYPE_FILETRANSFER_FAILED;
564                                        }
565                                        else if(!strncmp(info, "PARTNER_HANDLE ", 15))
566                                        {
567                                                info += 15;
568                                                if(sd->filetransfer_status) {
569                                                        switch(sd->filetransfer_status)
570                                                        {
571                                                                case SKYPE_FILETRANSFER_NEW:
572                                                                        imcb_log(ic, "The user %s offered a new file for you.", info);
573                                                                        break;
574                                                                case SKYPE_FILETRANSFER_FAILED:
575                                                                        imcb_log(ic, "Failed to transfer file from user %s.", info);
576                                                                        break;
577                                                        }
578                                                        sd->filetransfer_status = 0;
579                                                }
580                                        }
581                                }
582                        }
583                        else if(!strncmp(line, "CHAT ", 5))
584                        {
585                                char *id = strchr(line, ' ');
586                                if(++id)
587                                {
588                                        char *info = strchr(id, ' ');
589                                        if(info)
590                                                *info = '\0';
591                                        info++;
592                                        /* Remove fake chat if we created one in skype_chat_with() */
593                                        struct groupchat *gc = skype_chat_by_name(ic, "");
594                                        if(gc)
595                                                imcb_chat_free(gc);
596                                        if(!strcmp(info, "STATUS MULTI_SUBSCRIBED"))
597                                        {
598                                                imcb_chat_new( ic, id );
599                                                g_snprintf(buf, 1024, "GET CHAT %s ADDER\n", id);
600                                                skype_write(ic, buf, strlen(buf));
601                                                g_snprintf(buf, 1024, "GET CHAT %s TOPIC\n", id);
602                                                skype_write(ic, buf, strlen(buf));
603                                        }
604                                        else if(!strcmp(info, "STATUS DIALOG") && sd->groupchat_with)
605                                        {
606                                                gc = imcb_chat_new( ic, id );
607                                                /* According to the docs this
608                                                 * is necessary. However it
609                                                 * does not seem the situation
610                                                 * and it would open an extra
611                                                 * window on our client, so
612                                                 * just leave it out. */
613                                                /*g_snprintf(buf, 1024, "OPEN CHAT %s\n", id);
614                                                skype_write(ic, buf, strlen(buf));*/
615                                                g_snprintf(buf, 1024, "%s@skype.com", sd->groupchat_with);
616                                                imcb_chat_add_buddy(gc, buf);
617                                                imcb_chat_add_buddy(gc, sd->username);
618                                                g_free(sd->groupchat_with);
619                                                sd->groupchat_with = NULL;
620                                                g_snprintf(buf, 1024, "GET CHAT %s ADDER\n", id);
621                                                skype_write(ic, buf, strlen(buf));
622                                                g_snprintf(buf, 1024, "GET CHAT %s TOPIC\n", id);
623                                                skype_write(ic, buf, strlen(buf));
624                                        }
625                                        else if(!strcmp(info, "STATUS UNSUBSCRIBED"))
626                                        {
627                                                gc = skype_chat_by_name(ic, id);
628                                                if(gc)
629                                                        gc->data = (void*)FALSE;
630                                        }
631                                        else if(!strncmp(info, "ADDER ", 6))
632                                        {
633                                                info += 6;
634                                                g_free(sd->adder);
635                                                sd->adder = g_strdup_printf("%s@skype.com", info);
636                                        }
637                                        else if(!strncmp(info, "TOPIC ", 6))
638                                        {
639                                                info += 6;
640                                                gc = skype_chat_by_name(ic, id);
641                                                if(gc && (sd->adder || sd->topic_wait))
642                                                {
643                                                        if(sd->topic_wait)
644                                                        {
645                                                                sd->adder = g_strdup(sd->username);
646                                                                sd->topic_wait = 0;
647                                                        }
648                                                        imcb_chat_topic(gc, sd->adder, info, 0);
649                                                        g_free(sd->adder);
650                                                        sd->adder = NULL;
651                                                }
652                                        }
653                                        else if(!strncmp(info, "ACTIVEMEMBERS ", 14))
654                                        {
655                                                info += 14;
656                                                gc = skype_chat_by_name(ic, id);
657                                                /* Hack! We set ->data to TRUE
658                                                 * while we're on the channel
659                                                 * so that we won't rejoin
660                                                 * after a /part. */
661                                                if(gc && !gc->data)
662                                                {
663                                                        char **members = g_strsplit(info, " ", 0);
664                                                        int i;
665                                                        for(i=0;members[i];i++)
666                                                        {
667                                                                if(!strcmp(members[i], sd->username))
668                                                                        continue;
669                                                                g_snprintf(buf, 1024, "%s@skype.com", members[i]);
670                                                                if(!g_list_find_custom(gc->in_room, buf, (GCompareFunc)strcmp))
671                                                                        imcb_chat_add_buddy(gc, buf);
672                                                        }
673                                                        imcb_chat_add_buddy(gc, sd->username);
674                                                        g_strfreev(members);
675                                                }
676                                        }
677                                }
678                        }
679                        lineptr++;
680                }
681                g_strfreev(lines);
682        }
683        else if( st == 0 || ( st < 0 && !sockerr_again() ) )
684        {
685                closesocket( sd->fd );
686                sd->fd = -1;
687
688                imcb_error( ic, "Error while reading from server" );
689                imc_logout( ic, TRUE );
690                return FALSE;
691        }
692        return TRUE;
693}
694
695gboolean skype_start_stream( struct im_connection *ic )
696{
697        struct skype_data *sd = ic->proto_data;
698        char *buf;
699        int st;
700
701        if(!sd)
702                return FALSE;
703
704        if( sd->bfd <= 0 )
705                sd->bfd = b_input_add( sd->fd, GAIM_INPUT_READ, skype_read_callback, ic );
706
707        /* This will download all buddies. */
708        buf = g_strdup_printf("SEARCH FRIENDS\n");
709        st = skype_write( ic, buf, strlen( buf ) );
710        g_free(buf);
711        buf = g_strdup_printf("SET USERSTATUS ONLINE\n");
712        skype_write( ic, buf, strlen( buf ) );
713        g_free(buf);
714        return st;
715}
716
717gboolean skype_connected( gpointer data, gint source, b_input_condition cond )
718{
719        struct im_connection *ic = data;
720        imcb_connected(ic);
721        return skype_start_stream(ic);
722}
723
724static void skype_login( account_t *acc )
725{
726        struct im_connection *ic = imcb_new( acc );
727        struct skype_data *sd = g_new0( struct skype_data, 1 );
728
729        ic->proto_data = sd;
730
731        imcb_log( ic, "Connecting" );
732        sd->fd = proxy_connect(acc->server, set_getint( &acc->set, "port" ), skype_connected, ic );
733        sd->username = g_strdup( acc->user );
734
735        sd->ic = ic;
736}
737
738static void skype_logout( struct im_connection *ic )
739{
740        struct skype_data *sd = ic->proto_data;
741        char *buf;
742
743        buf = g_strdup_printf("SET USERSTATUS OFFLINE\n");
744        skype_write( ic, buf, strlen( buf ) );
745        g_free(buf);
746
747        g_free(sd->username);
748        g_free(sd->handle);
749        g_free(sd);
750        ic->proto_data = NULL;
751}
752
753static int skype_buddy_msg( struct im_connection *ic, char *who, char *message, int flags )
754{
755        char *buf, *ptr, *nick;
756        int st;
757
758        nick = g_strdup(who);
759        ptr = strchr(nick, '@');
760        if(ptr)
761                *ptr = '\0';
762
763        buf = g_strdup_printf("MESSAGE %s %s\n", nick, message);
764        g_free(nick);
765        st = skype_write( ic, buf, strlen( buf ) );
766        g_free(buf);
767
768        return st;
769}
770
771const struct skype_away_state *skype_away_state_by_name( char *name )
772{
773        int i;
774
775        for( i = 0; skype_away_state_list[i].full_name; i ++ )
776                if( g_strcasecmp( skype_away_state_list[i].full_name, name ) == 0 )
777                        return( skype_away_state_list + i );
778
779        return NULL;
780}
781
782static void skype_set_away( struct im_connection *ic, char *state_txt, char *message )
783{
784        const struct skype_away_state *state;
785        char *buf;
786
787        if( strcmp( state_txt, GAIM_AWAY_CUSTOM ) == 0 )
788                state = skype_away_state_by_name( "Away" );
789        else
790                state = skype_away_state_by_name( state_txt );
791        buf = g_strdup_printf("SET USERSTATUS %s\n", state->code);
792        skype_write( ic, buf, strlen( buf ) );
793        g_free(buf);
794}
795
796static GList *skype_away_states( struct im_connection *ic )
797{
798        static GList *l = NULL;
799        int i;
800       
801        if( l == NULL )
802                for( i = 0; skype_away_state_list[i].full_name; i ++ )
803                        l = g_list_append( l, (void*) skype_away_state_list[i].full_name );
804       
805        return l;
806}
807
808static void skype_add_buddy( struct im_connection *ic, char *who, char *group )
809{
810        char *buf, *nick, *ptr;
811
812        nick = g_strdup(who);
813        ptr = strchr(nick, '@');
814        if(ptr)
815                *ptr = '\0';
816        buf = g_strdup_printf("SET USER %s BUDDYSTATUS 2 Please authorize me\n", nick);
817        skype_write( ic, buf, strlen( buf ) );
818        g_free(nick);
819}
820
821static void skype_remove_buddy( struct im_connection *ic, char *who, char *group )
822{
823        char *buf, *nick, *ptr;
824
825        nick = g_strdup(who);
826        ptr = strchr(nick, '@');
827        if(ptr)
828                *ptr = '\0';
829        buf = g_strdup_printf("SET USER %s BUDDYSTATUS 1\n", nick);
830        skype_write( ic, buf, strlen( buf ) );
831        g_free(nick);
832}
833
834void skype_chat_msg( struct groupchat *gc, char *message, int flags )
835{
836        struct im_connection *ic = gc->ic;
837        char *buf;
838        buf = g_strdup_printf("CHATMESSAGE %s %s\n", gc->title, message);
839        skype_write( ic, buf, strlen( buf ) );
840        g_free(buf);
841}
842
843void skype_chat_leave( struct groupchat *gc )
844{
845        struct im_connection *ic = gc->ic;
846        char *buf;
847        buf = g_strdup_printf("ALTER CHAT %s LEAVE\n", gc->title);
848        skype_write( ic, buf, strlen( buf ) );
849        g_free(buf);
850        gc->data = (void*)TRUE;
851}
852
853void skype_chat_invite(struct groupchat *gc, char *who, char *message)
854{
855        struct im_connection *ic = gc->ic;
856        char *buf, *ptr, *nick;
857        nick = g_strdup(message);
858        ptr = strchr(nick, '@');
859        if(ptr)
860                *ptr = '\0';
861        buf = g_strdup_printf("ALTER CHAT %s ADDMEMBERS %s\n", gc->title, nick);
862        skype_write( ic, buf, strlen( buf ) );
863        g_free(buf);
864        g_free(nick);
865}
866
867void skype_chat_topic(struct groupchat *gc, char *message)
868{
869        struct im_connection *ic = gc->ic;
870        struct skype_data *sd = ic->proto_data;
871        char *buf;
872        buf = g_strdup_printf("ALTER CHAT %s SETTOPIC %s\n", gc->title, message);
873        skype_write( ic, buf, strlen( buf ) );
874        g_free(buf);
875        sd->topic_wait = 1;
876}
877
878struct groupchat *skype_chat_with(struct im_connection *ic, char *who)
879{
880        struct skype_data *sd = ic->proto_data;
881        char *ptr, *nick, *buf;
882        nick = g_strdup(who);
883        ptr = strchr(nick, '@');
884        if(ptr)
885                *ptr = '\0';
886        buf = g_strdup_printf("CHAT CREATE %s\n", nick);
887        skype_write(ic, buf, strlen(buf));
888        g_free(buf);
889        sd->groupchat_with = g_strdup(nick);
890        g_free(nick);
891        /* We create a fake chat for now. We will replace it with a real one in
892         * the real callback. */
893        return(imcb_chat_new( ic, "" ));
894}
895
896static void skype_get_info(struct im_connection *ic, char *who)
897{
898        char *ptr, *nick, *buf;
899        nick = g_strdup(who);
900        ptr = strchr(nick, '@');
901        if(ptr)
902                *ptr = '\0';
903        buf = g_strdup_printf("GET USER %s FULLNAME\n", nick);
904        skype_write(ic, buf, strlen(buf));
905        g_free(buf);
906        buf = g_strdup_printf("GET USER %s PHONE_HOME\n", nick);
907        skype_write(ic, buf, strlen(buf));
908        g_free(buf);
909        buf = g_strdup_printf("GET USER %s PHONE_OFFICE\n", nick);
910        skype_write(ic, buf, strlen(buf));
911        g_free(buf);
912        buf = g_strdup_printf("GET USER %s PHONE_MOBILE\n", nick);
913        skype_write(ic, buf, strlen(buf));
914        g_free(buf);
915        buf = g_strdup_printf("GET USER %s NROF_AUTHED_BUDDIES\n", nick);
916        skype_write(ic, buf, strlen(buf));
917        g_free(buf);
918        buf = g_strdup_printf("GET USER %s TIMEZONE\n", nick);
919        skype_write(ic, buf, strlen(buf));
920        g_free(buf);
921        buf = g_strdup_printf("GET USER %s LASTONLINETIMESTAMP\n", nick);
922        skype_write(ic, buf, strlen(buf));
923        g_free(buf);
924        buf = g_strdup_printf("GET USER %s BIRTHDAY\n", nick);
925        skype_write(ic, buf, strlen(buf));
926        g_free(buf);
927        buf = g_strdup_printf("GET USER %s SEX\n", nick);
928        skype_write(ic, buf, strlen(buf));
929        g_free(buf);
930        buf = g_strdup_printf("GET USER %s LANGUAGE\n", nick);
931        skype_write(ic, buf, strlen(buf));
932        g_free(buf);
933        buf = g_strdup_printf("GET USER %s COUNTRY\n", nick);
934        skype_write(ic, buf, strlen(buf));
935        g_free(buf);
936        buf = g_strdup_printf("GET USER %s PROVINCE\n", nick);
937        skype_write(ic, buf, strlen(buf));
938        g_free(buf);
939        buf = g_strdup_printf("GET USER %s CITY\n", nick);
940        skype_write(ic, buf, strlen(buf));
941        g_free(buf);
942        buf = g_strdup_printf("GET USER %s HOMEPAGE\n", nick);
943        skype_write(ic, buf, strlen(buf));
944        g_free(buf);
945        buf = g_strdup_printf("GET USER %s ABOUT\n", nick);
946        skype_write(ic, buf, strlen(buf));
947        g_free(buf);
948}
949
950void init_plugin(void)
951{
952        struct prpl *ret = g_new0( struct prpl, 1 );
953
954        ret->name = "skype";
955        ret->login = skype_login;
956        ret->init = skype_init;
957        ret->logout = skype_logout;
958        ret->buddy_msg = skype_buddy_msg;
959        ret->get_info = skype_get_info;
960        ret->away_states = skype_away_states;
961        ret->set_away = skype_set_away;
962        ret->add_buddy = skype_add_buddy;
963        ret->remove_buddy = skype_remove_buddy;
964        ret->chat_msg = skype_chat_msg;
965        ret->chat_leave = skype_chat_leave;
966        ret->chat_invite = skype_chat_invite;
967        ret->chat_with = skype_chat_with;
968        ret->handle_cmp = g_strcasecmp;
969        ret->chat_topic = skype_chat_topic;
970        register_protocol( ret );
971}
Note: See TracBrowser for help on using the repository browser.