source: skype/skype.c @ ed2e37f

Last change on this file since ed2e37f was ed2e37f, checked in by VMiklos <vmiklos@…>, at 2007-08-20T16:35:48Z

more error handling, no more SIGPIPE \o/ :)

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