source: skype/skype.c @ 6627d92

Last change on this file since 6627d92 was 6627d92, checked in by VMiklos <vmiklos@…>, at 2007-08-20T20:58:45Z

implement add/removing contacts

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