source: skype/skype.c @ 3c5aded

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

format last seen output properly

  • Property mode set to 100644
File size: 26.7 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                                                {
354                                                        /* this is currently buggy, says gmt+12 when I set gmt+1
355                                                        g_string_append_printf(st, "Local Time: %s\n", sd->info_tz); */
356                                                }
357                                                g_free(sd->info_tz);
358                                        }
359                                        if(sd->info_seen)
360                                        {
361                                                if(strlen(sd->info_seen))
362                                                {
363                                                        char ib[256];
364                                                        time_t it = atoi(sd->info_seen);
365                                                        struct tm *tm = localtime(&it);
366                                                        strftime(ib, 256, ("%Y. %m. %d. %H:%M"), tm);
367                                                        g_string_append_printf(st, "Last Seen: %s\n", ib);
368                                                }
369                                                g_free(sd->info_seen);
370                                        }
371                                        if(sd->info_birthday)
372                                        {
373                                                if(strlen(sd->info_birthday))
374                                                {
375                                                        // FIXME 19880101 -> str
376                                                        g_string_append_printf(st, "Birthday: %s\n", sd->info_birthday);
377                                                        g_string_append_printf(st, "Age:\n");
378                                                }
379                                                g_free(sd->info_birthday);
380                                        }
381                                        if(sd->info_sex)
382                                        {
383                                                if(strlen(sd->info_sex))
384                                                {
385                                                        // FIXME: UNKNOWN -> Unknown
386                                                        g_string_append_printf(st, "Gender: %s\n", sd->info_sex);
387                                                }
388                                                g_free(sd->info_sex);
389                                        }
390                                        if(sd->info_language)
391                                        {
392                                                if(strlen(sd->info_language))
393                                                {
394                                                        char *iptr = strchr(sd->info_language, ' ');
395                                                        if(iptr)
396                                                                iptr++;
397                                                        else
398                                                                iptr = sd->info_language;
399                                                        g_string_append_printf(st, "Language: %s\n", iptr);
400                                                }
401                                                g_free(sd->info_language);
402                                        }
403                                        if(sd->info_country)
404                                        {
405                                                if(strlen(sd->info_country))
406                                                {
407                                                        char *iptr = strchr(sd->info_country, ' ');
408                                                        if(iptr)
409                                                                iptr++;
410                                                        else
411                                                                iptr = sd->info_country;
412                                                        g_string_append_printf(st, "Country: %s\n", sd->iptr);
413                                                }
414                                                g_free(sd->info_country);
415                                        }
416                                        if(sd->info_province)
417                                        {
418                                                if(strlen(sd->info_province))
419                                                        g_string_append_printf(st, "Region: %s\n", sd->info_province);
420                                                g_free(sd->info_province);
421                                        }
422                                        if(sd->info_city)
423                                        {
424                                                if(strlen(sd->info_city))
425                                                        g_string_append_printf(st, "City: %s\n", sd->info_city);
426                                                g_free(sd->info_city);
427                                        }
428                                        if(sd->info_homepage)
429                                        {
430                                                if(strlen(sd->info_homepage))
431                                                        g_string_append_printf(st, "Homepage: %s\n", sd->info_homepage);
432                                                g_free(sd->info_homepage);
433                                        }
434                                        if(sd->info_about)
435                                        {
436                                                if(strlen(sd->info_about))
437                                                        g_string_append_printf(st, "%s\n", sd->info_about);
438                                                g_free(sd->info_about);
439                                        }
440                                        imcb_log(ic, "%s", st->str);
441                                        g_string_free(st, TRUE);
442                                }
443                        }
444                        else if(!strncmp(line, "CHATMESSAGE ", 12))
445                        {
446                                char *id = strchr(line, ' ');
447                                if(++id)
448                                {
449                                        char *info = strchr(id, ' ');
450                                        *info = '\0';
451                                        info++;
452                                        if(!strcmp(info, "STATUS RECEIVED"))
453                                        {
454                                                /* New message ID:
455                                                 * (1) Request its from field
456                                                 * (2) Request its body
457                                                 * (3) Request its type
458                                                 * (4) Query chatname
459                                                 */
460                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s FROM_HANDLE\n", id);
461                                                skype_write( ic, buf, strlen( buf ) );
462                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s BODY\n", id);
463                                                skype_write( ic, buf, strlen( buf ) );
464                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s TYPE\n", id);
465                                                skype_write( ic, buf, strlen( buf ) );
466                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s CHATNAME\n", id);
467                                                skype_write( ic, buf, strlen( buf ) );
468                                        }
469                                        else if(!strncmp(info, "FROM_HANDLE ", 12))
470                                        {
471                                                info += 12;
472                                                /* New from field value. Store
473                                                 * it, then we can later use it
474                                                 * when we got the message's
475                                                 * body. */
476                                                g_free(sd->handle);
477                                                sd->handle = g_strdup_printf("%s@skype.com", info);
478                                        }
479                                        else if(!strncmp(info, "EDITED_BY ", 10))
480                                        {
481                                                info += 10;
482                                                /* This is the same as
483                                                 * FROM_HANDLE, except that we
484                                                 * never request these lines
485                                                 * from Skype, we just get
486                                                 * them. */
487                                                g_free(sd->handle);
488                                                sd->handle = g_strdup_printf("%s@skype.com", info);
489                                        }
490                                        else if(!strncmp(info, "BODY ", 5))
491                                        {
492                                                info += 5;
493                                                sd->body = g_list_append(sd->body, g_strdup(info));
494                                        }
495                                        else if(!strncmp(info, "TYPE ", 5))
496                                        {
497                                                info += 5;
498                                                g_free(sd->type);
499                                                sd->type = g_strdup(info);
500                                        }
501                                        else if(!strncmp(info, "CHATNAME ", 9))
502                                        {
503                                                info += 9;
504                                                if(sd->handle && sd->body && sd->type)
505                                                {
506                                                        struct groupchat *gc = skype_chat_by_name(ic, info);
507                                                        int i;
508                                                        for(i=0;i<g_list_length(sd->body);i++)
509                                                        {
510                                                                char *body = g_list_nth_data(sd->body, i);
511                                                                if(!strcmp(sd->type, "SAID"))
512                                                                {
513                                                                        if(!gc)
514                                                                                /* Private message */
515                                                                                imcb_buddy_msg(ic, sd->handle, body, 0, 0);
516                                                                        else
517                                                                                /* Groupchat message */
518                                                                                imcb_chat_msg(gc, sd->handle, body, 0, 0);
519                                                                }
520                                                                else if(!strcmp(sd->type, "SETTOPIC"))
521                                                                {
522                                                                        if(gc)
523                                                                                imcb_chat_topic(gc, sd->handle, body, 0);
524                                                                }
525                                                                else if(!strcmp(sd->type, "LEFT"))
526                                                                {
527                                                                        if(gc)
528                                                                                imcb_chat_remove_buddy(gc, sd->handle, NULL);
529                                                                }
530                                                        }
531                                                        g_list_free(sd->body);
532                                                        sd->body = NULL;
533                                                }
534                                        }
535                                }
536                        }
537                        else if(!strncmp(line, "CALL ", 5))
538                        {
539                                char *id = strchr(line, ' ');
540                                if(++id)
541                                {
542                                        char *info = strchr(id, ' ');
543                                        *info = '\0';
544                                        info++;
545                                        if(!strcmp(info, "STATUS RINGING"))
546                                        {
547                                                g_snprintf(buf, 1024, "GET CALL %s PARTNER_HANDLE\n", id);
548                                                skype_write( ic, buf, strlen( buf ) );
549                                                sd->call_status = SKYPE_CALL_RINGING;
550                                        }
551                                        else if(!strcmp(info, "STATUS MISSED"))
552                                        {
553                                                g_snprintf(buf, 1024, "GET CALL %s PARTNER_HANDLE\n", id);
554                                                skype_write( ic, buf, strlen( buf ) );
555                                                sd->call_status = SKYPE_CALL_MISSED;
556                                        }
557                                        else if(!strncmp(info, "PARTNER_HANDLE ", 15))
558                                        {
559                                                info += 15;
560                                                if(sd->call_status) {
561                                                        switch(sd->call_status)
562                                                        {
563                                                                case SKYPE_CALL_RINGING:
564                                                                        imcb_log(ic, "The user %s is currently ringing you.", info);
565                                                                        break;
566                                                                case SKYPE_CALL_MISSED:
567                                                                        imcb_log(ic, "You have missed a call from user %s.", info);
568                                                                        break;
569                                                        }
570                                                        sd->call_status = 0;
571                                                }
572                                        }
573                                }
574                        }
575                        else if(!strncmp(line, "FILETRANSFER ", 13))
576                        {
577                                char *id = strchr(line, ' ');
578                                if(++id)
579                                {
580                                        char *info = strchr(id, ' ');
581                                        *info = '\0';
582                                        info++;
583                                        if(!strcmp(info, "STATUS NEW"))
584                                        {
585                                                g_snprintf(buf, 1024, "GET FILETRANSFER %s PARTNER_HANDLE\n", id);
586                                                skype_write( ic, buf, strlen( buf ) );
587                                                sd->filetransfer_status = SKYPE_FILETRANSFER_NEW;
588                                        }
589                                        else if(!strcmp(info, "STATUS FAILED"))
590                                        {
591                                                g_snprintf(buf, 1024, "GET FILETRANSFER %s PARTNER_HANDLE\n", id);
592                                                skype_write( ic, buf, strlen( buf ) );
593                                                sd->filetransfer_status = SKYPE_FILETRANSFER_FAILED;
594                                        }
595                                        else if(!strncmp(info, "PARTNER_HANDLE ", 15))
596                                        {
597                                                info += 15;
598                                                if(sd->filetransfer_status) {
599                                                        switch(sd->filetransfer_status)
600                                                        {
601                                                                case SKYPE_FILETRANSFER_NEW:
602                                                                        imcb_log(ic, "The user %s offered a new file for you.", info);
603                                                                        break;
604                                                                case SKYPE_FILETRANSFER_FAILED:
605                                                                        imcb_log(ic, "Failed to transfer file from user %s.", info);
606                                                                        break;
607                                                        }
608                                                        sd->filetransfer_status = 0;
609                                                }
610                                        }
611                                }
612                        }
613                        else if(!strncmp(line, "CHAT ", 5))
614                        {
615                                char *id = strchr(line, ' ');
616                                if(++id)
617                                {
618                                        char *info = strchr(id, ' ');
619                                        if(info)
620                                                *info = '\0';
621                                        info++;
622                                        /* Remove fake chat if we created one in skype_chat_with() */
623                                        struct groupchat *gc = skype_chat_by_name(ic, "");
624                                        if(gc)
625                                                imcb_chat_free(gc);
626                                        if(!strcmp(info, "STATUS MULTI_SUBSCRIBED"))
627                                        {
628                                                imcb_chat_new( ic, id );
629                                                g_snprintf(buf, 1024, "GET CHAT %s ADDER\n", id);
630                                                skype_write(ic, buf, strlen(buf));
631                                                g_snprintf(buf, 1024, "GET CHAT %s TOPIC\n", id);
632                                                skype_write(ic, buf, strlen(buf));
633                                        }
634                                        else if(!strcmp(info, "STATUS DIALOG") && sd->groupchat_with)
635                                        {
636                                                gc = imcb_chat_new( ic, id );
637                                                /* According to the docs this
638                                                 * is necessary. However it
639                                                 * does not seem the situation
640                                                 * and it would open an extra
641                                                 * window on our client, so
642                                                 * just leave it out. */
643                                                /*g_snprintf(buf, 1024, "OPEN CHAT %s\n", id);
644                                                skype_write(ic, buf, strlen(buf));*/
645                                                g_snprintf(buf, 1024, "%s@skype.com", sd->groupchat_with);
646                                                imcb_chat_add_buddy(gc, buf);
647                                                imcb_chat_add_buddy(gc, sd->username);
648                                                g_free(sd->groupchat_with);
649                                                sd->groupchat_with = NULL;
650                                                g_snprintf(buf, 1024, "GET CHAT %s ADDER\n", id);
651                                                skype_write(ic, buf, strlen(buf));
652                                                g_snprintf(buf, 1024, "GET CHAT %s TOPIC\n", id);
653                                                skype_write(ic, buf, strlen(buf));
654                                        }
655                                        else if(!strcmp(info, "STATUS UNSUBSCRIBED"))
656                                        {
657                                                gc = skype_chat_by_name(ic, id);
658                                                if(gc)
659                                                        gc->data = (void*)FALSE;
660                                        }
661                                        else if(!strncmp(info, "ADDER ", 6))
662                                        {
663                                                info += 6;
664                                                g_free(sd->adder);
665                                                sd->adder = g_strdup_printf("%s@skype.com", info);
666                                        }
667                                        else if(!strncmp(info, "TOPIC ", 6))
668                                        {
669                                                info += 6;
670                                                gc = skype_chat_by_name(ic, id);
671                                                if(gc && (sd->adder || sd->topic_wait))
672                                                {
673                                                        if(sd->topic_wait)
674                                                        {
675                                                                sd->adder = g_strdup(sd->username);
676                                                                sd->topic_wait = 0;
677                                                        }
678                                                        imcb_chat_topic(gc, sd->adder, info, 0);
679                                                        g_free(sd->adder);
680                                                        sd->adder = NULL;
681                                                }
682                                        }
683                                        else if(!strncmp(info, "ACTIVEMEMBERS ", 14))
684                                        {
685                                                info += 14;
686                                                gc = skype_chat_by_name(ic, id);
687                                                /* Hack! We set ->data to TRUE
688                                                 * while we're on the channel
689                                                 * so that we won't rejoin
690                                                 * after a /part. */
691                                                if(gc && !gc->data)
692                                                {
693                                                        char **members = g_strsplit(info, " ", 0);
694                                                        int i;
695                                                        for(i=0;members[i];i++)
696                                                        {
697                                                                if(!strcmp(members[i], sd->username))
698                                                                        continue;
699                                                                g_snprintf(buf, 1024, "%s@skype.com", members[i]);
700                                                                if(!g_list_find_custom(gc->in_room, buf, (GCompareFunc)strcmp))
701                                                                        imcb_chat_add_buddy(gc, buf);
702                                                        }
703                                                        imcb_chat_add_buddy(gc, sd->username);
704                                                        g_strfreev(members);
705                                                }
706                                        }
707                                }
708                        }
709                        lineptr++;
710                }
711                g_strfreev(lines);
712        }
713        else if( st == 0 || ( st < 0 && !sockerr_again() ) )
714        {
715                closesocket( sd->fd );
716                sd->fd = -1;
717
718                imcb_error( ic, "Error while reading from server" );
719                imc_logout( ic, TRUE );
720                return FALSE;
721        }
722        return TRUE;
723}
724
725gboolean skype_start_stream( struct im_connection *ic )
726{
727        struct skype_data *sd = ic->proto_data;
728        char *buf;
729        int st;
730
731        if(!sd)
732                return FALSE;
733
734        if( sd->bfd <= 0 )
735                sd->bfd = b_input_add( sd->fd, GAIM_INPUT_READ, skype_read_callback, ic );
736
737        /* This will download all buddies. */
738        buf = g_strdup_printf("SEARCH FRIENDS\n");
739        st = skype_write( ic, buf, strlen( buf ) );
740        g_free(buf);
741        buf = g_strdup_printf("SET USERSTATUS ONLINE\n");
742        skype_write( ic, buf, strlen( buf ) );
743        g_free(buf);
744        return st;
745}
746
747gboolean skype_connected( gpointer data, gint source, b_input_condition cond )
748{
749        struct im_connection *ic = data;
750        imcb_connected(ic);
751        return skype_start_stream(ic);
752}
753
754static void skype_login( account_t *acc )
755{
756        struct im_connection *ic = imcb_new( acc );
757        struct skype_data *sd = g_new0( struct skype_data, 1 );
758
759        ic->proto_data = sd;
760
761        imcb_log( ic, "Connecting" );
762        sd->fd = proxy_connect(acc->server, set_getint( &acc->set, "port" ), skype_connected, ic );
763        sd->username = g_strdup( acc->user );
764
765        sd->ic = ic;
766}
767
768static void skype_logout( struct im_connection *ic )
769{
770        struct skype_data *sd = ic->proto_data;
771        char *buf;
772
773        buf = g_strdup_printf("SET USERSTATUS OFFLINE\n");
774        skype_write( ic, buf, strlen( buf ) );
775        g_free(buf);
776
777        g_free(sd->username);
778        g_free(sd->handle);
779        g_free(sd);
780        ic->proto_data = NULL;
781}
782
783static int skype_buddy_msg( struct im_connection *ic, char *who, char *message, int flags )
784{
785        char *buf, *ptr, *nick;
786        int st;
787
788        nick = g_strdup(who);
789        ptr = strchr(nick, '@');
790        if(ptr)
791                *ptr = '\0';
792
793        buf = g_strdup_printf("MESSAGE %s %s\n", nick, message);
794        g_free(nick);
795        st = skype_write( ic, buf, strlen( buf ) );
796        g_free(buf);
797
798        return st;
799}
800
801const struct skype_away_state *skype_away_state_by_name( char *name )
802{
803        int i;
804
805        for( i = 0; skype_away_state_list[i].full_name; i ++ )
806                if( g_strcasecmp( skype_away_state_list[i].full_name, name ) == 0 )
807                        return( skype_away_state_list + i );
808
809        return NULL;
810}
811
812static void skype_set_away( struct im_connection *ic, char *state_txt, char *message )
813{
814        const struct skype_away_state *state;
815        char *buf;
816
817        if( strcmp( state_txt, GAIM_AWAY_CUSTOM ) == 0 )
818                state = skype_away_state_by_name( "Away" );
819        else
820                state = skype_away_state_by_name( state_txt );
821        buf = g_strdup_printf("SET USERSTATUS %s\n", state->code);
822        skype_write( ic, buf, strlen( buf ) );
823        g_free(buf);
824}
825
826static GList *skype_away_states( struct im_connection *ic )
827{
828        static GList *l = NULL;
829        int i;
830       
831        if( l == NULL )
832                for( i = 0; skype_away_state_list[i].full_name; i ++ )
833                        l = g_list_append( l, (void*) skype_away_state_list[i].full_name );
834       
835        return l;
836}
837
838static void skype_add_buddy( struct im_connection *ic, char *who, char *group )
839{
840        char *buf, *nick, *ptr;
841
842        nick = g_strdup(who);
843        ptr = strchr(nick, '@');
844        if(ptr)
845                *ptr = '\0';
846        buf = g_strdup_printf("SET USER %s BUDDYSTATUS 2 Please authorize me\n", nick);
847        skype_write( ic, buf, strlen( buf ) );
848        g_free(nick);
849}
850
851static void skype_remove_buddy( struct im_connection *ic, char *who, char *group )
852{
853        char *buf, *nick, *ptr;
854
855        nick = g_strdup(who);
856        ptr = strchr(nick, '@');
857        if(ptr)
858                *ptr = '\0';
859        buf = g_strdup_printf("SET USER %s BUDDYSTATUS 1\n", nick);
860        skype_write( ic, buf, strlen( buf ) );
861        g_free(nick);
862}
863
864void skype_chat_msg( struct groupchat *gc, char *message, int flags )
865{
866        struct im_connection *ic = gc->ic;
867        char *buf;
868        buf = g_strdup_printf("CHATMESSAGE %s %s\n", gc->title, message);
869        skype_write( ic, buf, strlen( buf ) );
870        g_free(buf);
871}
872
873void skype_chat_leave( struct groupchat *gc )
874{
875        struct im_connection *ic = gc->ic;
876        char *buf;
877        buf = g_strdup_printf("ALTER CHAT %s LEAVE\n", gc->title);
878        skype_write( ic, buf, strlen( buf ) );
879        g_free(buf);
880        gc->data = (void*)TRUE;
881}
882
883void skype_chat_invite(struct groupchat *gc, char *who, char *message)
884{
885        struct im_connection *ic = gc->ic;
886        char *buf, *ptr, *nick;
887        nick = g_strdup(message);
888        ptr = strchr(nick, '@');
889        if(ptr)
890                *ptr = '\0';
891        buf = g_strdup_printf("ALTER CHAT %s ADDMEMBERS %s\n", gc->title, nick);
892        skype_write( ic, buf, strlen( buf ) );
893        g_free(buf);
894        g_free(nick);
895}
896
897void skype_chat_topic(struct groupchat *gc, char *message)
898{
899        struct im_connection *ic = gc->ic;
900        struct skype_data *sd = ic->proto_data;
901        char *buf;
902        buf = g_strdup_printf("ALTER CHAT %s SETTOPIC %s\n", gc->title, message);
903        skype_write( ic, buf, strlen( buf ) );
904        g_free(buf);
905        sd->topic_wait = 1;
906}
907
908struct groupchat *skype_chat_with(struct im_connection *ic, char *who)
909{
910        struct skype_data *sd = ic->proto_data;
911        char *ptr, *nick, *buf;
912        nick = g_strdup(who);
913        ptr = strchr(nick, '@');
914        if(ptr)
915                *ptr = '\0';
916        buf = g_strdup_printf("CHAT CREATE %s\n", nick);
917        skype_write(ic, buf, strlen(buf));
918        g_free(buf);
919        sd->groupchat_with = g_strdup(nick);
920        g_free(nick);
921        /* We create a fake chat for now. We will replace it with a real one in
922         * the real callback. */
923        return(imcb_chat_new( ic, "" ));
924}
925
926static void skype_get_info(struct im_connection *ic, char *who)
927{
928        char *ptr, *nick, *buf;
929        nick = g_strdup(who);
930        ptr = strchr(nick, '@');
931        if(ptr)
932                *ptr = '\0';
933        buf = g_strdup_printf("GET USER %s FULLNAME\n", nick);
934        skype_write(ic, buf, strlen(buf));
935        g_free(buf);
936        buf = g_strdup_printf("GET USER %s PHONE_HOME\n", nick);
937        skype_write(ic, buf, strlen(buf));
938        g_free(buf);
939        buf = g_strdup_printf("GET USER %s PHONE_OFFICE\n", nick);
940        skype_write(ic, buf, strlen(buf));
941        g_free(buf);
942        buf = g_strdup_printf("GET USER %s PHONE_MOBILE\n", nick);
943        skype_write(ic, buf, strlen(buf));
944        g_free(buf);
945        buf = g_strdup_printf("GET USER %s NROF_AUTHED_BUDDIES\n", nick);
946        skype_write(ic, buf, strlen(buf));
947        g_free(buf);
948        buf = g_strdup_printf("GET USER %s TIMEZONE\n", nick);
949        skype_write(ic, buf, strlen(buf));
950        g_free(buf);
951        buf = g_strdup_printf("GET USER %s LASTONLINETIMESTAMP\n", nick);
952        skype_write(ic, buf, strlen(buf));
953        g_free(buf);
954        buf = g_strdup_printf("GET USER %s BIRTHDAY\n", nick);
955        skype_write(ic, buf, strlen(buf));
956        g_free(buf);
957        buf = g_strdup_printf("GET USER %s SEX\n", nick);
958        skype_write(ic, buf, strlen(buf));
959        g_free(buf);
960        buf = g_strdup_printf("GET USER %s LANGUAGE\n", nick);
961        skype_write(ic, buf, strlen(buf));
962        g_free(buf);
963        buf = g_strdup_printf("GET USER %s COUNTRY\n", nick);
964        skype_write(ic, buf, strlen(buf));
965        g_free(buf);
966        buf = g_strdup_printf("GET USER %s PROVINCE\n", nick);
967        skype_write(ic, buf, strlen(buf));
968        g_free(buf);
969        buf = g_strdup_printf("GET USER %s CITY\n", nick);
970        skype_write(ic, buf, strlen(buf));
971        g_free(buf);
972        buf = g_strdup_printf("GET USER %s HOMEPAGE\n", nick);
973        skype_write(ic, buf, strlen(buf));
974        g_free(buf);
975        buf = g_strdup_printf("GET USER %s ABOUT\n", nick);
976        skype_write(ic, buf, strlen(buf));
977        g_free(buf);
978}
979
980void init_plugin(void)
981{
982        struct prpl *ret = g_new0( struct prpl, 1 );
983
984        ret->name = "skype";
985        ret->login = skype_login;
986        ret->init = skype_init;
987        ret->logout = skype_logout;
988        ret->buddy_msg = skype_buddy_msg;
989        ret->get_info = skype_get_info;
990        ret->away_states = skype_away_states;
991        ret->set_away = skype_set_away;
992        ret->add_buddy = skype_add_buddy;
993        ret->remove_buddy = skype_remove_buddy;
994        ret->chat_msg = skype_chat_msg;
995        ret->chat_leave = skype_chat_leave;
996        ret->chat_invite = skype_chat_invite;
997        ret->chat_with = skype_chat_with;
998        ret->handle_cmp = g_strcasecmp;
999        ret->chat_topic = skype_chat_topic;
1000        register_protocol( ret );
1001}
Note: See TracBrowser for help on using the repository browser.