source: skype/skype.c @ dd8163e

Last change on this file since dd8163e was d3cbd17, checked in by VMiklos <vmiklos@…>, at 2007-08-21T14:10:25Z

implement skype_buddy_ask()

  • Property mode set to 100644
File size: 9.8 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
46struct skype_buddy_ask_data
47{
48        struct im_connection *ic;
49        char *handle;
50};
51
52static void skype_init( account_t *acc )
53{
54        set_t *s;
55
56        s = set_add( &acc->set, "port", SKYPE_PORT_DEFAULT, set_eval_int, acc );
57        s->flags |= ACC_SET_OFFLINE_ONLY;
58
59        s = set_add( &acc->set, "server", NULL, set_eval_account, acc );
60        s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
61}
62
63int skype_write( struct im_connection *ic, char *buf, int len )
64{
65        struct skype_data *sd = ic->proto_data;
66        struct pollfd pfd[1];
67
68        pfd[0].fd = sd->fd;
69        pfd[0].events = POLLOUT;
70
71        poll(pfd, 1, 1000);
72        if(pfd[0].revents & POLLHUP)
73        {
74                imcb_error( ic, "Could not connect to server" );
75                imc_logout( ic, TRUE );
76                return FALSE;
77        }
78        printf("write(): %s", buf);
79        write( sd->fd, buf, len );
80
81        return TRUE;
82}
83
84static void skype_buddy_ask_yes( gpointer w, struct skype_buddy_ask_data *bla )
85{
86        char *buf = g_strdup_printf("SET USER %s ISAUTHORIZED TRUE", bla->handle);
87        skype_write( bla->ic, buf, strlen( buf ) );
88        g_free(buf);
89        g_free(bla->handle);
90        g_free(bla);
91}
92
93static void skype_buddy_ask_no( gpointer w, struct skype_buddy_ask_data *bla )
94{
95        char *buf = g_strdup_printf("SET USER %s ISAUTHORIZED FALSE", bla->handle);
96        skype_write( bla->ic, buf, strlen( buf ) );
97        g_free(buf);
98        g_free(bla->handle);
99        g_free(bla);
100}
101
102void skype_buddy_ask( struct im_connection *ic, char *handle, char *message)
103{
104        struct skype_buddy_ask_data *bla = g_new0( struct skype_buddy_ask_data, 1 );
105        char *buf;
106
107        bla->ic = ic;
108        bla->handle = g_strdup(handle);
109
110        buf = g_strdup_printf( "The user %s wants to add you to his/her buddy list, saying: '%s'.", handle, message);
111        imcb_ask( ic, buf, bla, skype_buddy_ask_yes, skype_buddy_ask_no );
112        g_free( buf );
113}
114
115static gboolean skype_read_callback( gpointer data, gint fd, b_input_condition cond )
116{
117        struct im_connection *ic = data;
118        struct skype_data *sd = ic->proto_data;
119        char buf[1024];
120        int st;
121        char **lines, **lineptr, *line, *ptr;
122
123        if( !sd || sd->fd == -1 )
124                return FALSE;
125        st = read( sd->fd, buf, sizeof( buf ) );
126        if( st > 0 )
127        {
128                buf[st] = '\0';
129                printf("read(): '%s'\n", buf);
130                lines = g_strsplit(buf, "\n", 0);
131                lineptr = lines;
132                while((line = *lineptr))
133                {
134                        if(!strlen(line))
135                                break;
136                        printf("skype_read_callback() new line: '%s'\n", line);
137                        if(!strncmp(line, "USERS ", 6))
138                        {
139                                char **i;
140                                char **nicks;
141
142                                nicks = g_strsplit(line + 6, ", ", 0);
143                                i = nicks;
144                                while(*i)
145                                {
146                                        g_snprintf(buf, 1024, "GET USER %s ONLINESTATUS\n", *i);
147                                        skype_write( ic, buf, strlen( buf ) );
148                                        i++;
149                                }
150                                g_strfreev(nicks);
151                        }
152                        else if(!strncmp(line, "USER ", 5))
153                        {
154                                int flags = 0;
155                                char *status = strrchr(line, ' ');
156                                char *user = strchr(line, ' ');
157                                status++;
158                                ptr = strchr(++user, ' ');
159                                *ptr = '\0';
160                                ptr++;
161                                if(!strncmp(ptr, "ONLINESTATUS ", 13) && strcmp(user, sd->username) != 0 && strcmp(user, "echo123") != 0)
162                                {
163                                        ptr = g_strdup_printf("%s@skype.com", user);
164                                        imcb_add_buddy(ic, ptr, NULL);
165                                        if(strcmp(status, "OFFLINE") != 0)
166                                                flags |= OPT_LOGGED_IN;
167                                        if(strcmp(status, "ONLINE") != 0 && strcmp(status, "SKYPEME") != 0)
168                                                flags |= OPT_AWAY;
169                                        imcb_buddy_status(ic, ptr, flags, NULL, NULL);
170                                        g_free(ptr);
171                                }
172                                else if(!strncmp(ptr, "RECEIVEDAUTHREQUEST ", 20))
173                                {
174                                        char *message = ptr + 20;
175                                        if(strlen(message))
176                                                skype_buddy_ask(ic, user, message);
177                                }
178                                else if(!strncmp(ptr, "BUDDYSTATUS ", 12))
179                                {
180                                        char *st = ptr + 12;
181                                        if(!strcmp(st, "3"))
182                                        {
183                                                char *buf = g_strdup_printf("%s@skype.com", user);
184                                                imcb_add_buddy(ic, buf, NULL);
185                                                g_free(buf);
186                                        }
187                                }
188                        }
189                        else if(!strncmp(line, "CHATMESSAGE ", 12))
190                        {
191                                char *id = strchr(line, ' ');
192                                if(++id)
193                                {
194                                        char *info = strchr(id, ' ');
195                                        *info = '\0';
196                                        info++;
197                                        if(!strcmp(info, "STATUS RECEIVED"))
198                                        {
199                                                // new message, request its body
200                                                printf("new received message  #%s\n", id);
201                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s FROM_HANDLE\n", id);
202                                                skype_write( ic, buf, strlen( buf ) );
203                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s BODY\n", id);
204                                                skype_write( ic, buf, strlen( buf ) );
205                                                g_snprintf(buf, 1024, "SET CHATMESSAGE %s SEEN\n", id);
206                                                skype_write( ic, buf, strlen( buf ) );
207                                        }
208                                        else if(!strncmp(info, "FROM_HANDLE ", 12))
209                                        {
210                                                info += 12;
211                                                // new handle
212                                                sd->handle = g_strdup_printf("%s@skype.com", info);
213                                                printf("new handle: '%s'\n", info);
214                                        }
215                                        else if(!strncmp(info, "BODY ", 5))
216                                        {
217                                                info += 5;
218                                                // new body
219                                                printf("<%s> %s\n", sd->handle, info);
220                                                if(sd->handle)
221                                                        imcb_buddy_msg(ic, sd->handle, info, 0, 0);
222                                                g_free(sd->handle);
223                                                sd->handle = NULL;
224                                        }
225                                }
226                        }
227                        lineptr++;
228                }
229                g_strfreev(lines);
230        }
231        else if( st == 0 || ( st < 0 && !sockerr_again() ) )
232        {
233                closesocket( sd->fd );
234                sd->fd = -1;
235
236                imcb_error( ic, "Error while reading from server" );
237                imc_logout( ic, TRUE );
238                return FALSE;
239        }
240
241        /* EAGAIN/etc or a successful read. */
242        return TRUE;
243}
244
245gboolean skype_start_stream( struct im_connection *ic )
246{
247        struct skype_data *sd = ic->proto_data;
248        char *buf;
249        int st;
250
251        if(!sd)
252                return FALSE;
253
254        if( sd->r_inpa <= 0 )
255                sd->r_inpa = b_input_add( sd->fd, GAIM_INPUT_READ, skype_read_callback, ic );
256
257        // download buddies
258        buf = g_strdup_printf("SEARCH FRIENDS\n");
259        st = skype_write( ic, buf, strlen( buf ) );
260        g_free(buf);
261        buf = g_strdup_printf("SET USERSTATUS ONLINE\n");
262        skype_write( ic, buf, strlen( buf ) );
263        g_free(buf);
264        return st;
265}
266
267gboolean skype_connected( gpointer data, gint source, b_input_condition cond )
268{
269        struct im_connection *ic = data;
270        imcb_connected(ic);
271        return skype_start_stream(ic);
272}
273
274static void skype_login( account_t *acc )
275{
276        struct im_connection *ic = imcb_new( acc );
277        struct skype_data *sd = g_new0( struct skype_data, 1 );
278
279        ic->proto_data = sd;
280
281        imcb_log( ic, "Connecting" );
282        printf("%s:%d\n", acc->server, set_getint( &acc->set, "port"));
283        sd->fd = proxy_connect(acc->server, set_getint( &acc->set, "port" ), skype_connected, ic );
284        printf("sd->fd: %d\n", sd->fd);
285        /*imcb_add_buddy(ic, "test@skype.com", NULL);
286        imcb_buddy_status(ic, "test@skype.com", OPT_LOGGED_IN, NULL, NULL);
287        imcb_buddy_msg(ic, "test@skype.com", "test from skype plugin", 0, 0);*/
288        sd->username = g_strdup( acc->user );
289
290        sd->ic = ic;
291}
292
293static void skype_logout( struct im_connection *ic )
294{
295        struct skype_data *sd = ic->proto_data;
296        char *buf;
297
298        buf = g_strdup_printf("SET USERSTATUS OFFLINE\n");
299        skype_write( ic, buf, strlen( buf ) );
300        g_free(buf);
301
302        g_free(sd->username);
303        g_free(sd);
304        ic->proto_data = NULL;
305}
306
307static int skype_buddy_msg( struct im_connection *ic, char *who, char *message, int flags )
308{
309        char *buf, *ptr, *nick;
310        int st;
311
312        nick = g_strdup(who);
313        ptr = strchr(nick, '@');
314        if(ptr)
315                *ptr = '\0';
316
317        buf = g_strdup_printf("MESSAGE %s %s\n", nick, message);
318        g_free(nick);
319        st = skype_write( ic, buf, strlen( buf ) );
320        g_free(buf);
321
322        return st;
323}
324
325const struct skype_away_state *skype_away_state_by_name( char *name )
326{
327        int i;
328
329        for( i = 0; skype_away_state_list[i].full_name; i ++ )
330                if( g_strcasecmp( skype_away_state_list[i].full_name, name ) == 0 )
331                        return( skype_away_state_list + i );
332
333        return NULL;
334}
335
336static void skype_set_away( struct im_connection *ic, char *state_txt, char *message )
337{
338        const struct skype_away_state *state;
339        char *buf;
340
341        if( strcmp( state_txt, GAIM_AWAY_CUSTOM ) == 0 )
342                state = skype_away_state_by_name( "Away" );
343        else
344                state = skype_away_state_by_name( state_txt );
345        printf("would set to: '%s'\n", state->code);
346        buf = g_strdup_printf("SET USERSTATUS %s\n", state->code);
347        skype_write( ic, buf, strlen( buf ) );
348        g_free(buf);
349}
350
351static GList *skype_away_states( struct im_connection *ic )
352{
353        GList *l = NULL;
354        int i;
355       
356        for( i = 0; skype_away_state_list[i].full_name; i ++ )
357                l = g_list_append( l, (void*) skype_away_state_list[i].full_name );
358       
359        return l;
360}
361
362static void skype_add_buddy( struct im_connection *ic, char *who, char *group )
363{
364        char *buf, *nick, *ptr;
365
366        nick = g_strdup(who);
367        ptr = strchr(nick, '@');
368        if(ptr)
369                *ptr = '\0';
370        buf = g_strdup_printf("SET USER %s BUDDYSTATUS 2 Please authorize me\n", nick);
371        skype_write( ic, buf, strlen( buf ) );
372        printf("add '%s'\n", nick);
373        g_free(nick);
374}
375
376static void skype_remove_buddy( struct im_connection *ic, char *who, char *group )
377{
378        char *buf, *nick, *ptr;
379
380        nick = g_strdup(who);
381        ptr = strchr(nick, '@');
382        if(ptr)
383                *ptr = '\0';
384        buf = g_strdup_printf("SET USER %s BUDDYSTATUS 1\n", nick);
385        skype_write( ic, buf, strlen( buf ) );
386        printf("remove '%s'\n", nick);
387        g_free(nick);
388}
389
390void init_plugin(void)
391{
392        struct prpl *ret = g_new0( struct prpl, 1 );
393
394        ret->name = "skype";
395        ret->login = skype_login;
396        ret->init = skype_init;
397        ret->logout = skype_logout;
398        ret->buddy_msg = skype_buddy_msg;
399        ret->set_away = skype_set_away;
400        ret->away_states = skype_away_states;
401        ret->add_buddy = skype_add_buddy;
402        ret->remove_buddy = skype_remove_buddy;
403        ret->handle_cmp = g_strcasecmp;
404        register_protocol( ret );
405}
Note: See TracBrowser for help on using the repository browser.