source: skype/skype.c @ ecfbc5d

Last change on this file since ecfbc5d was ecfbc5d, checked in by VMiklos <vmiklos@…>, at 2007-08-22T16:12:28Z

skype_read_callback(): add notification about calls

  • Property mode set to 100644
File size: 10.8 KB
RevLine 
[7daec06]1/*
2 *  skype.c - Skype plugin for BitlBee
3 *
4 *  Copyright (c) 2007 by Miklos Vajna <vmiklos@frugalware.org>
[f06e3ac]5 *
[7daec06]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.
[f06e3ac]24 */
[7daec06]25
[f06e3ac]26#include <stdio.h>
[ed2e37f]27#include <poll.h>
[f06e3ac]28#include <bitlbee.h>
29
30#define SKYPE_PORT_DEFAULT "2727"
31
[7daec06]32/*
33 * Structures
34 */
35
[f06e3ac]36struct skype_data
37{
38        struct im_connection *ic;
[a3d6427]39        char *username;
[f06e3ac]40        int fd;
[877b6f4]41        int r_inpa;
[7daec06]42        /* When we receive a new message id, we query the handle, then the
43         * body. Store the handle here so that we imcb_buddy_msg() when we got
44         * the body. */
[77c1abe]45        char *handle;
[f06e3ac]46};
47
[adce2de]48struct skype_away_state
49{
50        char *code;
51        char *full_name;
52};
53
[7daec06]54struct skype_buddy_ask_data
55{
56        struct im_connection *ic;
57        char *handle;
58};
59
60/*
61 * Tables
62 */
63
[adce2de]64const struct skype_away_state skype_away_state_list[] =
65{
66        { "ONLINE",  "Online" },
67        { "SKYPEME",  "Skype Me" },
68        { "AWAY",   "Away" },
69        { "NA",    "Not available" },
70        { "DND",      "Do Not Disturb" },
71        { "INVISIBLE",      "Invisible" },
[23411c6]72        { "OFFLINE",      "Offline" },
73        { NULL, NULL}
[adce2de]74};
75
[7daec06]76/*
77 * Functions
78 */
[d3cbd17]79
[f06e3ac]80static void skype_init( account_t *acc )
81{
82        set_t *s;
83
84        s = set_add( &acc->set, "port", SKYPE_PORT_DEFAULT, set_eval_int, acc );
85        s->flags |= ACC_SET_OFFLINE_ONLY;
86
87        s = set_add( &acc->set, "server", NULL, set_eval_account, acc );
88        s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
89}
90
91int skype_write( struct im_connection *ic, char *buf, int len )
92{
93        struct skype_data *sd = ic->proto_data;
[1fb89e3]94        struct pollfd pfd[1];
95
96        pfd[0].fd = sd->fd;
97        pfd[0].events = POLLOUT;
[f06e3ac]98
[7daec06]99        /* This poll is necessary or we'll get a SIGPIPE when we write() to
100         * sd->fd. */
[1fb89e3]101        poll(pfd, 1, 1000);
102        if(pfd[0].revents & POLLHUP)
103        {
104                imcb_error( ic, "Could not connect to server" );
105                imc_logout( ic, TRUE );
106                return FALSE;
107        }
[9fd4241]108        write( sd->fd, buf, len );
[f06e3ac]109
[9fd4241]110        return TRUE;
[f06e3ac]111}
112
[d3cbd17]113static void skype_buddy_ask_yes( gpointer w, struct skype_buddy_ask_data *bla )
114{
115        char *buf = g_strdup_printf("SET USER %s ISAUTHORIZED TRUE", bla->handle);
116        skype_write( bla->ic, buf, strlen( buf ) );
117        g_free(buf);
118        g_free(bla->handle);
119        g_free(bla);
120}
121
122static void skype_buddy_ask_no( gpointer w, struct skype_buddy_ask_data *bla )
123{
124        char *buf = g_strdup_printf("SET USER %s ISAUTHORIZED FALSE", bla->handle);
125        skype_write( bla->ic, buf, strlen( buf ) );
126        g_free(buf);
127        g_free(bla->handle);
128        g_free(bla);
129}
130
131void skype_buddy_ask( struct im_connection *ic, char *handle, char *message)
132{
133        struct skype_buddy_ask_data *bla = g_new0( struct skype_buddy_ask_data, 1 );
134        char *buf;
135
136        bla->ic = ic;
137        bla->handle = g_strdup(handle);
138
139        buf = g_strdup_printf( "The user %s wants to add you to his/her buddy list, saying: '%s'.", handle, message);
140        imcb_ask( ic, buf, bla, skype_buddy_ask_yes, skype_buddy_ask_no );
141        g_free( buf );
142}
143
[1323e36]144static gboolean skype_read_callback( gpointer data, gint fd, b_input_condition cond )
145{
146        struct im_connection *ic = data;
147        struct skype_data *sd = ic->proto_data;
148        char buf[1024];
149        int st;
[9fd4241]150        char **lines, **lineptr, *line, *ptr;
[1323e36]151
[98bca36]152        if( !sd || sd->fd == -1 )
[1323e36]153                return FALSE;
[7daec06]154        /* Read the whole data. */
[1323e36]155        st = read( sd->fd, buf, sizeof( buf ) );
156        if( st > 0 )
157        {
158                buf[st] = '\0';
[7daec06]159                /* Then split it up to lines. */
[9fd4241]160                lines = g_strsplit(buf, "\n", 0);
161                lineptr = lines;
162                while((line = *lineptr))
163                {
164                        if(!strlen(line))
165                                break;
166                        if(!strncmp(line, "USERS ", 6))
167                        {
168                                char **i;
169                                char **nicks;
170
171                                nicks = g_strsplit(line + 6, ", ", 0);
172                                i = nicks;
173                                while(*i)
174                                {
175                                        g_snprintf(buf, 1024, "GET USER %s ONLINESTATUS\n", *i);
176                                        skype_write( ic, buf, strlen( buf ) );
177                                        i++;
178                                }
179                                g_strfreev(nicks);
180                        }
181                        else if(!strncmp(line, "USER ", 5))
182                        {
[adce2de]183                                int flags = 0;
[be975f8]184                                char *status = strrchr(line, ' ');
185                                char *user = strchr(line, ' ');
[adce2de]186                                status++;
[be975f8]187                                ptr = strchr(++user, ' ');
188                                *ptr = '\0';
[6627d92]189                                ptr++;
[7daec06]190                                if(!strncmp(ptr, "ONLINESTATUS ", 13) &&
191                                                strcmp(user, sd->username) != 0
192                                                && strcmp(user, "echo123") != 0)
[a3d6427]193                                {
194                                        ptr = g_strdup_printf("%s@skype.com", user);
195                                        imcb_add_buddy(ic, ptr, NULL);
196                                        if(strcmp(status, "OFFLINE") != 0)
197                                                flags |= OPT_LOGGED_IN;
198                                        if(strcmp(status, "ONLINE") != 0 && strcmp(status, "SKYPEME") != 0)
199                                                flags |= OPT_AWAY;
200                                        imcb_buddy_status(ic, ptr, flags, NULL, NULL);
201                                        g_free(ptr);
202                                }
[d3cbd17]203                                else if(!strncmp(ptr, "RECEIVEDAUTHREQUEST ", 20))
204                                {
205                                        char *message = ptr + 20;
206                                        if(strlen(message))
207                                                skype_buddy_ask(ic, user, message);
208                                }
209                                else if(!strncmp(ptr, "BUDDYSTATUS ", 12))
210                                {
211                                        char *st = ptr + 12;
212                                        if(!strcmp(st, "3"))
213                                        {
214                                                char *buf = g_strdup_printf("%s@skype.com", user);
215                                                imcb_add_buddy(ic, buf, NULL);
216                                                g_free(buf);
217                                        }
218                                }
[9fd4241]219                        }
[77c1abe]220                        else if(!strncmp(line, "CHATMESSAGE ", 12))
221                        {
222                                char *id = strchr(line, ' ');
223                                if(++id)
224                                {
225                                        char *info = strchr(id, ' ');
226                                        *info = '\0';
227                                        info++;
228                                        if(!strcmp(info, "STATUS RECEIVED"))
229                                        {
[7daec06]230                                                /* New message ID:
231                                                 * (1) Request its from field
232                                                 * (2) Request its body
233                                                 * (3) Mark it as seen
234                                                 */
[77c1abe]235                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s FROM_HANDLE\n", id);
236                                                skype_write( ic, buf, strlen( buf ) );
237                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s BODY\n", id);
238                                                skype_write( ic, buf, strlen( buf ) );
[62bb4e4]239                                                g_snprintf(buf, 1024, "SET CHATMESSAGE %s SEEN\n", id);
240                                                skype_write( ic, buf, strlen( buf ) );
[77c1abe]241                                        }
242                                        else if(!strncmp(info, "FROM_HANDLE ", 12))
243                                        {
244                                                info += 12;
[7daec06]245                                                /* New from field value. Store
246                                                 * it, then we can later use it
247                                                 * when we got the message's
248                                                 * body. */
[77c1abe]249                                                sd->handle = g_strdup_printf("%s@skype.com", info);
250                                        }
251                                        else if(!strncmp(info, "BODY ", 5))
252                                        {
253                                                info += 5;
[ed2e37f]254                                                if(sd->handle)
[7daec06]255                                                {
256                                                        /* New body, we have everything to use imcb_buddy_msg() now! */
[ed2e37f]257                                                        imcb_buddy_msg(ic, sd->handle, info, 0, 0);
[7daec06]258                                                        g_free(sd->handle);
259                                                        sd->handle = NULL;
260                                                }
[77c1abe]261                                        }
262                                }
263                        }
[ecfbc5d]264                        else if(!strncmp(line, "CALL ", 5))
265                        {
266                                char *id = strchr(line, ' ');
267                                if(++id)
268                                {
269                                        char *info = strchr(id, ' ');
270                                        *info = '\0';
271                                        info++;
272                                        if(!strcmp(info, "STATUS RINGING"))
273                                        {
274                                                g_snprintf(buf, 1024, "GET CALL %s PARTNER_HANDLE\n", id);
275                                                skype_write( ic, buf, strlen( buf ) );
276                                        }
277                                        else if(!strncmp(info, "PARTNER_HANDLE ", 15))
278                                        {
279                                                info += 15;
280                                                imcb_log(ic, "The user %s is currently ringing you.", info);
281                                        }
282                                }
283                        }
[9fd4241]284                        lineptr++;
285                }
286                g_strfreev(lines);
[1323e36]287        }
288        else if( st == 0 || ( st < 0 && !sockerr_again() ) )
289        {
290                closesocket( sd->fd );
291                sd->fd = -1;
292
293                imcb_error( ic, "Error while reading from server" );
294                imc_logout( ic, TRUE );
295                return FALSE;
296        }
297        return TRUE;
298}
299
[f06e3ac]300gboolean skype_start_stream( struct im_connection *ic )
301{
[1323e36]302        struct skype_data *sd = ic->proto_data;
[f06e3ac]303        char *buf;
304        int st;
305
[1fb89e3]306        if(!sd)
307                return FALSE;
308
[1323e36]309        if( sd->r_inpa <= 0 )
310                sd->r_inpa = b_input_add( sd->fd, GAIM_INPUT_READ, skype_read_callback, ic );
311
[7daec06]312        /* This will download all buddies. */
[9fd4241]313        buf = g_strdup_printf("SEARCH FRIENDS\n");
[f06e3ac]314        st = skype_write( ic, buf, strlen( buf ) );
315        g_free(buf);
[348a3a2]316        buf = g_strdup_printf("SET USERSTATUS ONLINE\n");
317        skype_write( ic, buf, strlen( buf ) );
318        g_free(buf);
[f06e3ac]319        return st;
320}
321
322gboolean skype_connected( gpointer data, gint source, b_input_condition cond )
323{
324        struct im_connection *ic = data;
[ed2e37f]325        imcb_connected(ic);
[f06e3ac]326        return skype_start_stream(ic);
327}
328
329static void skype_login( account_t *acc )
330{
331        struct im_connection *ic = imcb_new( acc );
332        struct skype_data *sd = g_new0( struct skype_data, 1 );
333
334        ic->proto_data = sd;
335
336        imcb_log( ic, "Connecting" );
337        sd->fd = proxy_connect(acc->server, set_getint( &acc->set, "port" ), skype_connected, ic );
[a3d6427]338        sd->username = g_strdup( acc->user );
[f06e3ac]339
340        sd->ic = ic;
341}
342
343static void skype_logout( struct im_connection *ic )
344{
345        struct skype_data *sd = ic->proto_data;
[98bca36]346        char *buf;
347
348        buf = g_strdup_printf("SET USERSTATUS OFFLINE\n");
349        skype_write( ic, buf, strlen( buf ) );
350        g_free(buf);
351
[a3d6427]352        g_free(sd->username);
[f06e3ac]353        g_free(sd);
[98bca36]354        ic->proto_data = NULL;
[f06e3ac]355}
356
[93ece66]357static int skype_buddy_msg( struct im_connection *ic, char *who, char *message, int flags )
358{
[77c1abe]359        char *buf, *ptr, *nick;
[93ece66]360        int st;
361
[cbec0d6]362        nick = g_strdup(who);
[77c1abe]363        ptr = strchr(nick, '@');
[0bb1b7f]364        if(ptr)
365                *ptr = '\0';
[93ece66]366
[77c1abe]367        buf = g_strdup_printf("MESSAGE %s %s\n", nick, message);
368        g_free(nick);
[93ece66]369        st = skype_write( ic, buf, strlen( buf ) );
370        g_free(buf);
371
372        return st;
373}
374
[23411c6]375const struct skype_away_state *skype_away_state_by_name( char *name )
376{
377        int i;
378
379        for( i = 0; skype_away_state_list[i].full_name; i ++ )
380                if( g_strcasecmp( skype_away_state_list[i].full_name, name ) == 0 )
381                        return( skype_away_state_list + i );
382
383        return NULL;
384}
385
[f06e3ac]386static void skype_set_away( struct im_connection *ic, char *state_txt, char *message )
387{
[23411c6]388        const struct skype_away_state *state;
389        char *buf;
390
391        if( strcmp( state_txt, GAIM_AWAY_CUSTOM ) == 0 )
392                state = skype_away_state_by_name( "Away" );
393        else
394                state = skype_away_state_by_name( state_txt );
395        buf = g_strdup_printf("SET USERSTATUS %s\n", state->code);
396        skype_write( ic, buf, strlen( buf ) );
397        g_free(buf);
[f06e3ac]398}
399
400static GList *skype_away_states( struct im_connection *ic )
401{
[23411c6]402        GList *l = NULL;
[adce2de]403        int i;
404       
[23411c6]405        for( i = 0; skype_away_state_list[i].full_name; i ++ )
406                l = g_list_append( l, (void*) skype_away_state_list[i].full_name );
[adce2de]407       
[f06e3ac]408        return l;
409}
410
411static void skype_add_buddy( struct im_connection *ic, char *who, char *group )
412{
[6627d92]413        char *buf, *nick, *ptr;
414
[cbec0d6]415        nick = g_strdup(who);
[6627d92]416        ptr = strchr(nick, '@');
417        if(ptr)
418                *ptr = '\0';
419        buf = g_strdup_printf("SET USER %s BUDDYSTATUS 2 Please authorize me\n", nick);
420        skype_write( ic, buf, strlen( buf ) );
421        g_free(nick);
[f06e3ac]422}
423
424static void skype_remove_buddy( struct im_connection *ic, char *who, char *group )
425{
[6627d92]426        char *buf, *nick, *ptr;
427
[cbec0d6]428        nick = g_strdup(who);
[6627d92]429        ptr = strchr(nick, '@');
430        if(ptr)
431                *ptr = '\0';
432        buf = g_strdup_printf("SET USER %s BUDDYSTATUS 1\n", nick);
433        skype_write( ic, buf, strlen( buf ) );
434        g_free(nick);
[f06e3ac]435}
436
437void init_plugin(void)
438{
439        struct prpl *ret = g_new0( struct prpl, 1 );
440
441        ret->name = "skype";
442        ret->login = skype_login;
443        ret->init = skype_init;
444        ret->logout = skype_logout;
[93ece66]445        ret->buddy_msg = skype_buddy_msg;
[f06e3ac]446        ret->away_states = skype_away_states;
[7daec06]447        ret->set_away = skype_set_away;
[f06e3ac]448        ret->add_buddy = skype_add_buddy;
449        ret->remove_buddy = skype_remove_buddy;
450        ret->handle_cmp = g_strcasecmp;
451        register_protocol( ret );
452}
Note: See TracBrowser for help on using the repository browser.