source: protocols/msn/msn_util.c @ 81186cab

Last change on this file since 81186cab was 17a6ee9, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-04-11T14:37:06Z

Including DCC stuff again, with a wonderful extra layer of abstraction.
Some hooks are missing so sending files doesn't work yet. Receiving also
still seems to have some issues. On the plus side, at least the MSN/Jabber
modules work again.

  • Property mode set to 100644
File size: 8.9 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2004 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* MSN module - Miscellaneous utilities                                 */
8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23  Suite 330, Boston, MA  02111-1307  USA
24*/
25
26#include "nogaim.h"
27#include "msn.h"
28#include <ctype.h>
29
30int msn_write( struct im_connection *ic, char *s, int len )
31{
32        struct msn_data *md = ic->proto_data;
33        int st;
34       
35        st = write( md->fd, s, len );
36        if( st != len )
37        {
38                imcb_error( ic, "Short write() to main server" );
39                imc_logout( ic, TRUE );
40                return( 0 );
41        }
42       
43        return( 1 );
44}
45
46int msn_logged_in( struct im_connection *ic )
47{
48        imcb_connected( ic );
49       
50        return( 0 );
51}
52
53int msn_buddy_list_add( struct im_connection *ic, char *list, char *who, char *realname_ )
54{
55        struct msn_data *md = ic->proto_data;
56        char buf[1024], *realname;
57       
58        realname = msn_http_encode( realname_ );
59       
60        g_snprintf( buf, sizeof( buf ), "ADD %d %s %s %s\r\n", ++md->trId, list, who, realname );
61        if( msn_write( ic, buf, strlen( buf ) ) )
62        {
63                g_free( realname );
64               
65                return( 1 );
66        }
67       
68        g_free( realname );
69       
70        return( 0 );
71}
72
73int msn_buddy_list_remove( struct im_connection *ic, char *list, char *who )
74{
75        struct msn_data *md = ic->proto_data;
76        char buf[1024];
77       
78        g_snprintf( buf, sizeof( buf ), "REM %d %s %s\r\n", ++md->trId, list, who );
79        if( msn_write( ic, buf, strlen( buf ) ) )
80                return( 1 );
81       
82        return( 0 );
83}
84
85struct msn_buddy_ask_data
86{
87        struct im_connection *ic;
88        char *handle;
89        char *realname;
90};
91
92static void msn_buddy_ask_yes( void *data )
93{
94        struct msn_buddy_ask_data *bla = data;
95       
96        msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname );
97       
98        imcb_ask_add( bla->ic, bla->handle, NULL );
99       
100        g_free( bla->handle );
101        g_free( bla->realname );
102        g_free( bla );
103}
104
105static void msn_buddy_ask_no( void *data )
106{
107        struct msn_buddy_ask_data *bla = data;
108       
109        msn_buddy_list_add( bla->ic, "BL", bla->handle, bla->realname );
110       
111        g_free( bla->handle );
112        g_free( bla->realname );
113        g_free( bla );
114}
115
116void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname )
117{
118        struct msn_buddy_ask_data *bla = g_new0( struct msn_buddy_ask_data, 1 );
119        char buf[1024];
120       
121        bla->ic = ic;
122        bla->handle = g_strdup( handle );
123        bla->realname = g_strdup( realname );
124       
125        g_snprintf( buf, sizeof( buf ),
126                    "The user %s (%s) wants to add you to his/her buddy list.",
127                    handle, realname );
128        imcb_ask( ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no );
129}
130
131char *msn_findheader( char *text, char *header, int len )
132{
133        int hlen = strlen( header ), i;
134        char *ret;
135       
136        if( len == 0 )
137                len = strlen( text );
138       
139        i = 0;
140        while( ( i + hlen ) < len )
141        {
142                /* Maybe this is a bit over-commented, but I just hate this part... */
143                if( g_strncasecmp( text + i, header, hlen ) == 0 )
144                {
145                        /* Skip to the (probable) end of the header */
146                        i += hlen;
147                       
148                        /* Find the first non-[: \t] character */
149                        while( i < len && ( text[i] == ':' || text[i] == ' ' || text[i] == '\t' ) ) i ++;
150                       
151                        /* Make sure we're still inside the string */
152                        if( i >= len ) return( NULL );
153                       
154                        /* Save the position */
155                        ret = text + i;
156                       
157                        /* Search for the end of this line */
158                        while( i < len && text[i] != '\r' && text[i] != '\n' ) i ++;
159                       
160                        /* Make sure we're still inside the string */
161                        if( i >= len ) return( NULL );
162                       
163                        /* Copy the found data */
164                        return( g_strndup( ret, text + i - ret ) );
165                }
166               
167                /* This wasn't the header we were looking for, skip to the next line. */
168                while( i < len && ( text[i] != '\r' && text[i] != '\n' ) ) i ++;
169                while( i < len && ( text[i] == '\r' || text[i] == '\n' ) ) i ++;
170               
171                /* End of headers? */
172                if( ( i >= 4 && strncmp( text + i - 4, "\r\n\r\n", 4 ) == 0 ) ||
173                    ( i >= 2 && ( strncmp( text + i - 2, "\n\n", 2 ) == 0 ||   
174                                  strncmp( text + i - 2, "\r\r", 2 ) == 0 ) ) )
175                {
176                        break;
177                }
178        }
179       
180        return( NULL );
181}
182
183/* *NOT* thread-safe, but that's not a problem for now... */
184char **msn_linesplit( char *line )
185{
186        static char **ret = NULL;
187        static int size = 3;
188        int i, n = 0;
189       
190        if( ret == NULL )
191                ret = g_new0( char*, size );
192       
193        for( i = 0; line[i] && line[i] == ' '; i ++ );
194        if( line[i] )
195        {
196                ret[n++] = line + i;
197                for( i ++; line[i]; i ++ )
198                {
199                        if( line[i] == ' ' )
200                                line[i] = 0;
201                        else if( line[i] != ' ' && !line[i-1] )
202                                ret[n++] = line + i;
203                       
204                        if( n >= size )
205                                ret = g_renew( char*, ret, size += 2 );
206                }
207        }
208        ret[n] = NULL;
209       
210        return( ret );
211}
212
213/* This one handles input from a MSN Messenger server. Both the NS and SB servers usually give
214   commands, but sometimes they give additional data (payload). This function tries to handle
215   this all in a nice way and send all data to the right places. */
216
217/* Return values: -1: Read error, abort connection.
218                   0: Command reported error; Abort *immediately*. (The connection does not exist anymore)
219                   1: OK */
220
221int msn_handler( struct msn_handler_data *h )
222{
223        int st;
224       
225        h->rxq = g_renew( char, h->rxq, h->rxlen + 1024 );
226        st = read( h->fd, h->rxq + h->rxlen, 1024 );
227        h->rxlen += st;
228       
229        if( st <= 0 )
230                return( -1 );
231       
232        while( st )
233        {
234                int i;
235               
236                if( h->msglen == 0 )
237                {
238                        for( i = 0; i < h->rxlen; i ++ )
239                        {
240                                if( h->rxq[i] == '\r' || h->rxq[i] == '\n' )
241                                {
242                                        char *cmd_text, **cmd;
243                                        int count;
244                                       
245                                        cmd_text = g_strndup( h->rxq, i );
246                                        cmd = msn_linesplit( cmd_text );
247                                        for( count = 0; cmd[count]; count ++ );
248                                        st = h->exec_command( h->data, cmd, count );
249                                        g_free( cmd_text );
250                                       
251                                        /* If the connection broke, don't continue. We don't even exist anymore. */
252                                        if( !st )
253                                                return( 0 );
254                                       
255                                        if( h->msglen )
256                                                h->cmd_text = g_strndup( h->rxq, i );
257                                       
258                                        /* Skip to the next non-emptyline */
259                                        while( i < h->rxlen && ( h->rxq[i] == '\r' || h->rxq[i] == '\n' ) ) i ++;
260                                       
261                                        break;
262                                }
263                        }
264                       
265                        /* If we reached the end of the buffer, there's still an incomplete command there.
266                           Return and wait for more data. */
267                        if( i == h->rxlen && h->rxq[i-1] != '\r' && h->rxq[i-1] != '\n' )
268                                break;
269                }
270                else
271                {
272                        char *msg, **cmd;
273                        int count;
274                       
275                        /* Do we have the complete message already? */
276                        if( h->msglen > h->rxlen )
277                                break;
278                       
279                        msg = g_strndup( h->rxq, h->msglen );
280                        cmd = msn_linesplit( h->cmd_text );
281                        for( count = 0; cmd[count]; count ++ );
282                       
283                        st = h->exec_message( h->data, msg, h->msglen, cmd, count );
284                        g_free( msg );
285                        g_free( h->cmd_text );
286                        h->cmd_text = NULL;
287                       
288                        if( !st )
289                                return( 0 );
290                       
291                        i = h->msglen;
292                        h->msglen = 0;
293                }
294               
295                /* More data after this block? */
296                if( i < h->rxlen )
297                {
298                        char *tmp;
299                       
300                        tmp = g_memdup( h->rxq + i, h->rxlen - i );
301                        g_free( h->rxq );
302                        h->rxq = tmp;
303                        h->rxlen -= i;
304                        i = 0;
305                }
306                else
307                /* If not, reset the rx queue and get lost. */
308                {
309                        g_free( h->rxq );
310                        h->rxq = g_new0( char, 1 );
311                        h->rxlen = 0;
312                        return( 1 );
313                }
314        }
315       
316        return( 1 );
317}
318
319/* The difference between this function and the normal http_encode() function
320   is that this one escapes every 7-bit ASCII character because this is said
321   to avoid some lame server-side checks when setting a real-name. Also,
322   non-ASCII characters are not escaped because MSN servers don't seem to
323   appreciate that! */
324char *msn_http_encode( const char *input )
325{
326        char *ret, *s;
327        int i;
328       
329        ret = s = g_new0( char, strlen( input ) * 3 + 1 );
330        for( i = 0; input[i]; i ++ )
331                if( input[i] & 128 )
332                {
333                        *s = input[i];
334                        s ++;
335                }
336                else
337                {
338                        g_snprintf( s, 4, "%%%02X", input[i] );
339                        s += 3;
340                }
341       
342        return ret;
343}
344
345void msn_msgq_purge( struct im_connection *ic, GSList **list )
346{
347        struct msn_message *m;
348        GString *ret;
349        GSList *l;
350       
351        l = *list;
352        if( l == NULL )
353                return;
354       
355        m = l->data;
356        ret = g_string_sized_new( 1024 );
357        g_string_printf( ret, "Warning: Cleaning up MSN (switchboard) connection with unsent "
358                              "messages to %s:", m->who ? m->who : "unknown recipient" );
359       
360        while( l )
361        {
362                m = l->data;
363               
364                g_string_append_printf( ret, "\n%s", m->text );
365               
366                g_free( m->who );
367                g_free( m->text );
368                g_free( m );
369               
370                l = l->next;
371        }
372        g_slist_free( *list );
373        *list = NULL;
374       
375        imcb_log( ic, "%s", ret->str );
376        g_string_free( ret, TRUE );
377}
Note: See TracBrowser for help on using the repository browser.