source: skype/skype.c @ 98bca36

Last change on this file since 98bca36 was 98bca36, checked in by VMiklos <vmiklos@…>, at 2007-08-20T22:37:17Z

prevent a segfault in skype_read_callback()

  • Property mode set to 100644
File size: 8.3 KB
Line 
1/*
2 * This is the most simple possible BitlBee plugin. To use, compile it as
3 * a shared library and place it in the plugin directory:
4 *
5 * gcc -o example.so -shared example.c `pkg-config --cflags bitlbee`
6 * cp example.so /usr/local/lib/bitlbee
7 */
8#include <stdio.h>
9#include <poll.h>
10#include <bitlbee.h>
11
12#define SKYPE_PORT_DEFAULT "2727"
13
14struct skype_data
15{
16        struct im_connection *ic;
17        char *username;
18        int fd;
19        char *txq;
20        int tx_len;
21        int r_inpa, w_inpa;
22        // when we receive a new message id, we query the handle, then the body
23        // store the handle here
24        // TODO: it would be nicer to use a hashmap for this or something
25        char *handle;
26};
27
28struct skype_away_state
29{
30        char *code;
31        char *full_name;
32};
33
34const struct skype_away_state skype_away_state_list[] =
35{
36        { "ONLINE",  "Online" },
37        { "SKYPEME",  "Skype Me" },
38        { "AWAY",   "Away" },
39        { "NA",    "Not available" },
40        { "DND",      "Do Not Disturb" },
41        { "INVISIBLE",      "Invisible" },
42        { "OFFLINE",      "Offline" },
43        { NULL, NULL}
44};
45
46static void skype_init( account_t *acc )
47{
48        set_t *s;
49
50        s = set_add( &acc->set, "port", SKYPE_PORT_DEFAULT, set_eval_int, acc );
51        s->flags |= ACC_SET_OFFLINE_ONLY;
52
53        s = set_add( &acc->set, "server", NULL, set_eval_account, acc );
54        s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
55}
56
57int skype_write( struct im_connection *ic, char *buf, int len )
58{
59        struct skype_data *sd = ic->proto_data;
60
61        printf("write(): %s", buf);
62        write( sd->fd, buf, len );
63
64        return TRUE;
65}
66
67static gboolean skype_read_callback( gpointer data, gint fd, b_input_condition cond )
68{
69        struct im_connection *ic = data;
70        struct skype_data *sd = ic->proto_data;
71        char buf[1024];
72        int st;
73        char **lines, **lineptr, *line, *ptr;
74
75        if( !sd || sd->fd == -1 )
76                return FALSE;
77        st = read( sd->fd, buf, sizeof( buf ) );
78        if( st > 0 )
79        {
80                buf[st] = '\0';
81                printf("read(): '%s'\n", buf);
82                lines = g_strsplit(buf, "\n", 0);
83                lineptr = lines;
84                while((line = *lineptr))
85                {
86                        if(!strlen(line))
87                                break;
88                        printf("skype_read_callback() new line: '%s'\n", line);
89                        if(!strncmp(line, "USERS ", 6))
90                        {
91                                char **i;
92                                char **nicks;
93
94                                nicks = g_strsplit(line + 6, ", ", 0);
95                                i = nicks;
96                                while(*i)
97                                {
98                                        g_snprintf(buf, 1024, "GET USER %s ONLINESTATUS\n", *i);
99                                        skype_write( ic, buf, strlen( buf ) );
100                                        i++;
101                                }
102                                g_strfreev(nicks);
103                        }
104                        else if(!strncmp(line, "USER ", 5))
105                        {
106                                int flags = 0;
107                                char *status = strrchr(line, ' ');
108                                char *user = strchr(line, ' ');
109                                status++;
110                                ptr = strchr(++user, ' ');
111                                *ptr = '\0';
112                                ptr++;
113                                if(!strncmp(ptr, "ONLINESTATUS ", 13) && strcmp(user, sd->username) != 0 && strcmp(user, "echo123") != 0)
114                                {
115                                        ptr = g_strdup_printf("%s@skype.com", user);
116                                        imcb_add_buddy(ic, ptr, NULL);
117                                        if(strcmp(status, "OFFLINE") != 0)
118                                                flags |= OPT_LOGGED_IN;
119                                        if(strcmp(status, "ONLINE") != 0 && strcmp(status, "SKYPEME") != 0)
120                                                flags |= OPT_AWAY;
121                                        imcb_buddy_status(ic, ptr, flags, NULL, NULL);
122                                        g_free(ptr);
123                                }
124                        }
125                        else if(!strncmp(line, "CHATMESSAGE ", 12))
126                        {
127                                char *id = strchr(line, ' ');
128                                if(++id)
129                                {
130                                        char *info = strchr(id, ' ');
131                                        *info = '\0';
132                                        info++;
133                                        if(!strcmp(info, "STATUS RECEIVED"))
134                                        {
135                                                // new message, request its body
136                                                printf("new received message  #%s\n", id);
137                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s FROM_HANDLE\n", id);
138                                                skype_write( ic, buf, strlen( buf ) );
139                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s BODY\n", id);
140                                                skype_write( ic, buf, strlen( buf ) );
141                                                g_snprintf(buf, 1024, "SET CHATMESSAGE %s SEEN\n", id);
142                                                skype_write( ic, buf, strlen( buf ) );
143                                        }
144                                        else if(!strncmp(info, "FROM_HANDLE ", 12))
145                                        {
146                                                info += 12;
147                                                // new handle
148                                                sd->handle = g_strdup_printf("%s@skype.com", info);
149                                                printf("new handle: '%s'\n", info);
150                                        }
151                                        else if(!strncmp(info, "BODY ", 5))
152                                        {
153                                                info += 5;
154                                                // new body
155                                                printf("<%s> %s\n", sd->handle, info);
156                                                if(sd->handle)
157                                                        imcb_buddy_msg(ic, sd->handle, info, 0, 0);
158                                                g_free(sd->handle);
159                                                sd->handle = NULL;
160                                        }
161                                }
162                        }
163                        lineptr++;
164                }
165                g_strfreev(lines);
166        }
167        else if( st == 0 || ( st < 0 && !sockerr_again() ) )
168        {
169                closesocket( sd->fd );
170                sd->fd = -1;
171
172                imcb_error( ic, "Error while reading from server" );
173                imc_logout( ic, TRUE );
174                return FALSE;
175        }
176
177        /* EAGAIN/etc or a successful read. */
178        return TRUE;
179}
180
181gboolean skype_start_stream( struct im_connection *ic )
182{
183        struct skype_data *sd = ic->proto_data;
184        char *buf;
185        int st;
186
187        if( sd->r_inpa <= 0 )
188                sd->r_inpa = b_input_add( sd->fd, GAIM_INPUT_READ, skype_read_callback, ic );
189
190        // download buddies
191        buf = g_strdup_printf("SEARCH FRIENDS\n");
192        st = skype_write( ic, buf, strlen( buf ) );
193        g_free(buf);
194        return st;
195}
196
197gboolean skype_connected( gpointer data, gint source, b_input_condition cond )
198{
199        struct im_connection *ic = data;
200        struct skype_data *sd = ic->proto_data;
201        struct pollfd pfd[1];
202
203        pfd[0].fd = sd->fd;
204        pfd[0].events = POLLOUT;
205
206        poll(pfd, 1, 1000);
207        if(pfd[0].revents & POLLHUP)
208        {
209                imcb_error( ic, "Could not connect to server" );
210                imc_logout( ic, TRUE );
211                return FALSE;
212        }
213        imcb_connected(ic);
214        return skype_start_stream(ic);
215}
216
217static void skype_login( account_t *acc )
218{
219        struct im_connection *ic = imcb_new( acc );
220        struct skype_data *sd = g_new0( struct skype_data, 1 );
221
222        ic->proto_data = sd;
223
224        imcb_log( ic, "Connecting" );
225        printf("%s:%d\n", acc->server, set_getint( &acc->set, "port"));
226        sd->fd = proxy_connect(acc->server, set_getint( &acc->set, "port" ), skype_connected, ic );
227        printf("sd->fd: %d\n", sd->fd);
228        /*imcb_add_buddy(ic, "test@skype.com", NULL);
229        imcb_buddy_status(ic, "test@skype.com", OPT_LOGGED_IN, NULL, NULL);
230        imcb_buddy_msg(ic, "test@skype.com", "test from skype plugin", 0, 0);*/
231        sd->username = g_strdup( acc->user );
232
233        sd->ic = ic;
234}
235
236static void skype_logout( struct im_connection *ic )
237{
238        struct skype_data *sd = ic->proto_data;
239        char *buf;
240
241        buf = g_strdup_printf("SET USERSTATUS OFFLINE\n");
242        skype_write( ic, buf, strlen( buf ) );
243        g_free(buf);
244
245        g_free(sd->username);
246        g_free(sd);
247        ic->proto_data = NULL;
248}
249
250static int skype_buddy_msg( struct im_connection *ic, char *who, char *message, int flags )
251{
252        char *buf, *ptr, *nick;
253        int st;
254
255        nick = g_strdup(who);
256        ptr = strchr(nick, '@');
257        if(ptr)
258                *ptr = '\0';
259
260        buf = g_strdup_printf("MESSAGE %s %s\n", nick, message);
261        g_free(nick);
262        st = skype_write( ic, buf, strlen( buf ) );
263        g_free(buf);
264
265        return st;
266}
267
268const struct skype_away_state *skype_away_state_by_name( char *name )
269{
270        int i;
271
272        for( i = 0; skype_away_state_list[i].full_name; i ++ )
273                if( g_strcasecmp( skype_away_state_list[i].full_name, name ) == 0 )
274                        return( skype_away_state_list + i );
275
276        return NULL;
277}
278
279static void skype_set_away( struct im_connection *ic, char *state_txt, char *message )
280{
281        const struct skype_away_state *state;
282        char *buf;
283
284        if( strcmp( state_txt, GAIM_AWAY_CUSTOM ) == 0 )
285                state = skype_away_state_by_name( "Away" );
286        else
287                state = skype_away_state_by_name( state_txt );
288        printf("would set to: '%s'\n", state->code);
289        buf = g_strdup_printf("SET USERSTATUS %s\n", state->code);
290        skype_write( ic, buf, strlen( buf ) );
291        g_free(buf);
292}
293
294static GList *skype_away_states( struct im_connection *ic )
295{
296        GList *l = NULL;
297        int i;
298       
299        for( i = 0; skype_away_state_list[i].full_name; i ++ )
300                l = g_list_append( l, (void*) skype_away_state_list[i].full_name );
301       
302        return l;
303}
304
305static void skype_add_buddy( struct im_connection *ic, char *who, char *group )
306{
307        char *buf, *nick, *ptr;
308
309        nick = g_strdup(who);
310        ptr = strchr(nick, '@');
311        if(ptr)
312                *ptr = '\0';
313        buf = g_strdup_printf("SET USER %s BUDDYSTATUS 2 Please authorize me\n", nick);
314        skype_write( ic, buf, strlen( buf ) );
315        printf("add '%s'\n", nick);
316        g_free(nick);
317}
318
319static void skype_remove_buddy( struct im_connection *ic, char *who, char *group )
320{
321        char *buf, *nick, *ptr;
322
323        nick = g_strdup(who);
324        ptr = strchr(nick, '@');
325        if(ptr)
326                *ptr = '\0';
327        buf = g_strdup_printf("SET USER %s BUDDYSTATUS 1\n", nick);
328        skype_write( ic, buf, strlen( buf ) );
329        printf("remove '%s'\n", nick);
330        g_free(nick);
331}
332
333void init_plugin(void)
334{
335        struct prpl *ret = g_new0( struct prpl, 1 );
336
337        ret->name = "skype";
338        ret->login = skype_login;
339        ret->init = skype_init;
340        ret->logout = skype_logout;
341        ret->buddy_msg = skype_buddy_msg;
342        ret->set_away = skype_set_away;
343        ret->away_states = skype_away_states;
344        ret->add_buddy = skype_add_buddy;
345        ret->remove_buddy = skype_remove_buddy;
346        ret->handle_cmp = g_strcasecmp;
347        register_protocol( ret );
348}
Note: See TracBrowser for help on using the repository browser.