source: skype/skype.c @ 348a3a2

Last change on this file since 348a3a2 was 348a3a2, checked in by VMiklos <vmiklos@…>, at 2007-08-20T22:38:06Z

use SET USERSTATUS on login/logout

  • 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
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        buf = g_strdup_printf("SET USERSTATUS ONLINE\n");
195        skype_write( ic, buf, strlen( buf ) );
196        g_free(buf);
197        return st;
198}
199
200gboolean skype_connected( gpointer data, gint source, b_input_condition cond )
201{
202        struct im_connection *ic = data;
203        struct skype_data *sd = ic->proto_data;
204        struct pollfd pfd[1];
205
206        pfd[0].fd = sd->fd;
207        pfd[0].events = POLLOUT;
208
209        poll(pfd, 1, 1000);
210        if(pfd[0].revents & POLLHUP)
211        {
212                imcb_error( ic, "Could not connect to server" );
213                imc_logout( ic, TRUE );
214                return FALSE;
215        }
216        imcb_connected(ic);
217        return skype_start_stream(ic);
218}
219
220static void skype_login( account_t *acc )
221{
222        struct im_connection *ic = imcb_new( acc );
223        struct skype_data *sd = g_new0( struct skype_data, 1 );
224
225        ic->proto_data = sd;
226
227        imcb_log( ic, "Connecting" );
228        printf("%s:%d\n", acc->server, set_getint( &acc->set, "port"));
229        sd->fd = proxy_connect(acc->server, set_getint( &acc->set, "port" ), skype_connected, ic );
230        printf("sd->fd: %d\n", sd->fd);
231        /*imcb_add_buddy(ic, "test@skype.com", NULL);
232        imcb_buddy_status(ic, "test@skype.com", OPT_LOGGED_IN, NULL, NULL);
233        imcb_buddy_msg(ic, "test@skype.com", "test from skype plugin", 0, 0);*/
234        sd->username = g_strdup( acc->user );
235
236        sd->ic = ic;
237}
238
239static void skype_logout( struct im_connection *ic )
240{
241        struct skype_data *sd = ic->proto_data;
242        char *buf;
243
244        buf = g_strdup_printf("SET USERSTATUS OFFLINE\n");
245        skype_write( ic, buf, strlen( buf ) );
246        g_free(buf);
247
248        g_free(sd->username);
249        g_free(sd);
250        ic->proto_data = NULL;
251}
252
253static int skype_buddy_msg( struct im_connection *ic, char *who, char *message, int flags )
254{
255        char *buf, *ptr, *nick;
256        int st;
257
258        nick = g_strdup(who);
259        ptr = strchr(nick, '@');
260        if(ptr)
261                *ptr = '\0';
262
263        buf = g_strdup_printf("MESSAGE %s %s\n", nick, message);
264        g_free(nick);
265        st = skype_write( ic, buf, strlen( buf ) );
266        g_free(buf);
267
268        return st;
269}
270
271const struct skype_away_state *skype_away_state_by_name( char *name )
272{
273        int i;
274
275        for( i = 0; skype_away_state_list[i].full_name; i ++ )
276                if( g_strcasecmp( skype_away_state_list[i].full_name, name ) == 0 )
277                        return( skype_away_state_list + i );
278
279        return NULL;
280}
281
282static void skype_set_away( struct im_connection *ic, char *state_txt, char *message )
283{
284        const struct skype_away_state *state;
285        char *buf;
286
287        if( strcmp( state_txt, GAIM_AWAY_CUSTOM ) == 0 )
288                state = skype_away_state_by_name( "Away" );
289        else
290                state = skype_away_state_by_name( state_txt );
291        printf("would set to: '%s'\n", state->code);
292        buf = g_strdup_printf("SET USERSTATUS %s\n", state->code);
293        skype_write( ic, buf, strlen( buf ) );
294        g_free(buf);
295}
296
297static GList *skype_away_states( struct im_connection *ic )
298{
299        GList *l = NULL;
300        int i;
301       
302        for( i = 0; skype_away_state_list[i].full_name; i ++ )
303                l = g_list_append( l, (void*) skype_away_state_list[i].full_name );
304       
305        return l;
306}
307
308static void skype_add_buddy( struct im_connection *ic, char *who, char *group )
309{
310        char *buf, *nick, *ptr;
311
312        nick = g_strdup(who);
313        ptr = strchr(nick, '@');
314        if(ptr)
315                *ptr = '\0';
316        buf = g_strdup_printf("SET USER %s BUDDYSTATUS 2 Please authorize me\n", nick);
317        skype_write( ic, buf, strlen( buf ) );
318        printf("add '%s'\n", nick);
319        g_free(nick);
320}
321
322static void skype_remove_buddy( struct im_connection *ic, char *who, char *group )
323{
324        char *buf, *nick, *ptr;
325
326        nick = g_strdup(who);
327        ptr = strchr(nick, '@');
328        if(ptr)
329                *ptr = '\0';
330        buf = g_strdup_printf("SET USER %s BUDDYSTATUS 1\n", nick);
331        skype_write( ic, buf, strlen( buf ) );
332        printf("remove '%s'\n", nick);
333        g_free(nick);
334}
335
336void init_plugin(void)
337{
338        struct prpl *ret = g_new0( struct prpl, 1 );
339
340        ret->name = "skype";
341        ret->login = skype_login;
342        ret->init = skype_init;
343        ret->logout = skype_logout;
344        ret->buddy_msg = skype_buddy_msg;
345        ret->set_away = skype_set_away;
346        ret->away_states = skype_away_states;
347        ret->add_buddy = skype_add_buddy;
348        ret->remove_buddy = skype_remove_buddy;
349        ret->handle_cmp = g_strcasecmp;
350        register_protocol( ret );
351}
Note: See TracBrowser for help on using the repository browser.