source: skype/skype.c @ 72f697b

Last change on this file since 72f697b was a3d6427, checked in by VMiklos <vmiklos@…>, at 2007-08-20T17:25:32Z

bugfix: we can't join to &bitlbee twice

  • Property mode set to 100644
File size: 6.9 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                                if(strcmp(user, sd->username) != 0)
112                                {
113                                        ptr = g_strdup_printf("%s@skype.com", user);
114                                        imcb_add_buddy(ic, ptr, NULL);
115                                        if(strcmp(status, "OFFLINE") != 0)
116                                                flags |= OPT_LOGGED_IN;
117                                        if(strcmp(status, "ONLINE") != 0 && strcmp(status, "SKYPEME") != 0)
118                                                flags |= OPT_AWAY;
119                                        imcb_buddy_status(ic, ptr, flags, NULL, NULL);
120                                        g_free(ptr);
121                                }
122                        }
123                        else if(!strncmp(line, "CHATMESSAGE ", 12))
124                        {
125                                char *id = strchr(line, ' ');
126                                if(++id)
127                                {
128                                        char *info = strchr(id, ' ');
129                                        *info = '\0';
130                                        info++;
131                                        if(!strcmp(info, "STATUS RECEIVED"))
132                                        {
133                                                // new message, request its body
134                                                printf("new received message  #%s\n", id);
135                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s FROM_HANDLE\n", id);
136                                                skype_write( ic, buf, strlen( buf ) );
137                                                g_snprintf(buf, 1024, "GET CHATMESSAGE %s BODY\n", id);
138                                                skype_write( ic, buf, strlen( buf ) );
139                                        }
140                                        else if(!strncmp(info, "FROM_HANDLE ", 12))
141                                        {
142                                                info += 12;
143                                                // new handle
144                                                sd->handle = g_strdup_printf("%s@skype.com", info);
145                                                printf("new handle: '%s'\n", info);
146                                        }
147                                        else if(!strncmp(info, "BODY ", 5))
148                                        {
149                                                info += 5;
150                                                // new body
151                                                printf("<%s> %s\n", sd->handle, info);
152                                                if(sd->handle)
153                                                        imcb_buddy_msg(ic, sd->handle, info, 0, 0);
154                                                g_free(sd->handle);
155                                                sd->handle = NULL;
156                                        }
157                                }
158                        }
159                        lineptr++;
160                }
161                g_strfreev(lines);
162        }
163        else if( st == 0 || ( st < 0 && !sockerr_again() ) )
164        {
165                closesocket( sd->fd );
166                sd->fd = -1;
167
168                imcb_error( ic, "Error while reading from server" );
169                imc_logout( ic, TRUE );
170                return FALSE;
171        }
172
173        /* EAGAIN/etc or a successful read. */
174        return TRUE;
175}
176
177gboolean skype_start_stream( struct im_connection *ic )
178{
179        struct skype_data *sd = ic->proto_data;
180        char *buf;
181        int st;
182
183        if( sd->r_inpa <= 0 )
184                sd->r_inpa = b_input_add( sd->fd, GAIM_INPUT_READ, skype_read_callback, ic );
185
186        // download buddies
187        buf = g_strdup_printf("SEARCH FRIENDS\n");
188        st = skype_write( ic, buf, strlen( buf ) );
189        g_free(buf);
190        return st;
191}
192
193gboolean skype_connected( gpointer data, gint source, b_input_condition cond )
194{
195        struct im_connection *ic = data;
196        struct skype_data *sd = ic->proto_data;
197        struct pollfd pfd[1];
198
199        pfd[0].fd = sd->fd;
200        pfd[0].events = POLLOUT;
201
202        poll(pfd, 1, 1000);
203        if(pfd[0].revents & POLLHUP)
204        {
205                imcb_error( ic, "Could not connect to server" );
206                imc_logout( ic, TRUE );
207                return FALSE;
208        }
209        imcb_connected(ic);
210        return skype_start_stream(ic);
211}
212
213static void skype_login( account_t *acc )
214{
215        struct im_connection *ic = imcb_new( acc );
216        struct skype_data *sd = g_new0( struct skype_data, 1 );
217
218        ic->proto_data = sd;
219
220        imcb_log( ic, "Connecting" );
221        printf("%s:%d\n", acc->server, set_getint( &acc->set, "port"));
222        sd->fd = proxy_connect(acc->server, set_getint( &acc->set, "port" ), skype_connected, ic );
223        printf("sd->fd: %d\n", sd->fd);
224        /*imcb_add_buddy(ic, "test@skype.com", NULL);
225        imcb_buddy_status(ic, "test@skype.com", OPT_LOGGED_IN, NULL, NULL);
226        imcb_buddy_msg(ic, "test@skype.com", "test from skype plugin", 0, 0);*/
227        sd->username = g_strdup( acc->user );
228
229        sd->ic = ic;
230}
231
232static void skype_logout( struct im_connection *ic )
233{
234        struct skype_data *sd = ic->proto_data;
235        g_free(sd->username);
236        g_free(sd);
237}
238
239static int skype_buddy_msg( struct im_connection *ic, char *who, char *message, int flags )
240{
241        char *buf, *ptr, *nick;
242        int st;
243
244        nick = g_strdup_printf("%s", who);
245        ptr = strchr(nick, '@');
246        if(ptr)
247                *ptr = '\0';
248
249        buf = g_strdup_printf("MESSAGE %s %s\n", nick, message);
250        g_free(nick);
251        st = skype_write( ic, buf, strlen( buf ) );
252        g_free(buf);
253
254        return st;
255}
256
257static void skype_set_away( struct im_connection *ic, char *state_txt, char *message )
258{
259}
260
261static GList *skype_away_states( struct im_connection *ic )
262{
263        static GList *l = NULL;
264        int i;
265       
266        if( l == NULL )
267                for( i = 0; skype_away_state_list[i].full_name; i ++ )
268                        l = g_list_append( l, (void*) skype_away_state_list[i].full_name );
269       
270        return l;
271}
272
273static void skype_add_buddy( struct im_connection *ic, char *who, char *group )
274{
275}
276
277static void skype_remove_buddy( struct im_connection *ic, char *who, char *group )
278{
279}
280
281void init_plugin(void)
282{
283        struct prpl *ret = g_new0( struct prpl, 1 );
284
285        ret->name = "skype";
286        ret->login = skype_login;
287        ret->init = skype_init;
288        ret->logout = skype_logout;
289        ret->buddy_msg = skype_buddy_msg;
290        ret->away_states = skype_away_states;
291        ret->add_buddy = skype_add_buddy;
292        ret->remove_buddy = skype_remove_buddy;
293        ret->away_states = skype_away_states;
294        ret->set_away = skype_set_away;
295        ret->handle_cmp = g_strcasecmp;
296        register_protocol( ret );
297}
Note: See TracBrowser for help on using the repository browser.