source: skype/skype.c @ 1fb89e3

Last change on this file since 1fb89e3 was 1fb89e3, checked in by VMiklos <vmiklos@…>, at 2007-08-20T22:56:56Z

move the poll() usage to skype_write()

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