source: protocols/msn/sb.c @ 664bac3

Last change on this file since 664bac3 was 6b13103, checked in by dequis <dx@…>, at 2015-01-16T19:50:23Z

Replace isdigit/isalpha/.../tolower/toupper with glib variants

This fixes warnings about passing signed chars to them (apparently they
are implemented as macros that do array lookups without checks in some
platforms, yay)

Specifically:

functions=isalnum|isalpha|isdigit|isspace|isxdigit|tolower|toupper
sed -ir "s/$functions/g_ascii_&/g" /*.c

  • Property mode set to 100644
File size: 19.6 KB
RevLine 
[b7d3cc34]1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
[79bb7e4]4  * Copyright 2002-2012 Wilmer van der Gaast and others                *
[b7d3cc34]5  \********************************************************************/
6
7/* MSN module - Switchboard server callbacks and 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;
[6f10697]22  if not, write to the Free Software Foundation, Inc., 51 Franklin St.,
23  Fifth Floor, Boston, MA  02110-1301  USA
[b7d3cc34]24*/
25
26#include <ctype.h>
27#include "nogaim.h"
28#include "msn.h"
29#include "md5.h"
[e5a8118]30#include "soap.h"
[5fecede]31#include "invitation.h"
[b7d3cc34]32
[ba9edaa]33static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond );
[bae0617]34static int msn_sb_command( struct msn_handler_data *handler, char **cmd, int num_parts );
35static int msn_sb_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts );
[b7d3cc34]36
[64768d4]37int msn_sb_write( struct msn_switchboard *sb, const char *fmt, ... )
[b7d3cc34]38{
[64768d4]39        va_list params;
40        char *out;
41        size_t len;
[b7d3cc34]42        int st;
43       
[64768d4]44        va_start( params, fmt );
45        out = g_strdup_vprintf( fmt, params );
46        va_end( params );
47       
[523fb23]48        if( getenv( "BITLBEE_DEBUG" ) )
[eb54f56]49                fprintf( stderr, "->SB%d:%s\n", sb->fd, out );
[523fb23]50       
[64768d4]51        len = strlen( out );
52        st = write( sb->fd, out, len );
53        g_free( out );
[b7d3cc34]54        if( st != len )
55        {
56                msn_sb_destroy( sb );
[64768d4]57                return 0;
[b7d3cc34]58        }
59       
[64768d4]60        return 1;
[b7d3cc34]61}
62
[a830512]63int msn_sb_write_msg( struct im_connection *ic, struct msn_message *m )
64{
65        struct msn_data *md = ic->proto_data;
66        struct msn_switchboard *sb;
67
68        /* FIXME: *CHECK* the reliability of using spare sb's! */
69        if( ( sb = msn_sb_spare( ic ) ) )
70        {
71                debug( "Trying to use a spare switchboard to message %s", m->who );
72               
73                sb->who = g_strdup( m->who );
[64768d4]74                if( msn_sb_write( sb, "CAL %d %s\r\n", ++sb->trId, m->who ) )
[a830512]75                {
76                        /* He/She should join the switchboard soon, let's queue the message. */
77                        sb->msgq = g_slist_append( sb->msgq, m );
78                        return( 1 );
79                }
80        }
81       
82        debug( "Creating a new switchboard to message %s", m->who );
83       
84        /* If we reach this line, there was no spare switchboard, so let's make one. */
[64768d4]85        if( !msn_ns_write( ic, -1, "XFR %d SB\r\n", ++md->trId ) )
[a830512]86        {
87                g_free( m->who );
88                g_free( m->text );
89                g_free( m );
90               
91                return( 0 );
92        }
93       
94        /* And queue the message to md. We'll pick it up when the switchboard comes up. */
95        md->msgq = g_slist_append( md->msgq, m );
96       
97        /* FIXME: If the switchboard creation fails, the message will not be sent. */
98       
99        return( 1 );
100}
101
[0da65d5]102struct msn_switchboard *msn_sb_create( struct im_connection *ic, char *host, int port, char *key, int session )
[b7d3cc34]103{
[0da65d5]104        struct msn_data *md = ic->proto_data;
[b7d3cc34]105        struct msn_switchboard *sb = g_new0( struct msn_switchboard, 1 );
106       
107        sb->fd = proxy_connect( host, port, msn_sb_connected, sb );
108        if( sb->fd < 0 )
109        {
110                g_free( sb );
111                return( NULL );
112        }
113       
[0da65d5]114        sb->ic = ic;
[b7d3cc34]115        sb->key = g_strdup( key );
116        sb->session = session;
117       
118        msn_switchboards = g_slist_append( msn_switchboards, sb );
119        md->switchboards = g_slist_append( md->switchboards, sb );
120       
121        return( sb );
122}
123
[79bb7e4]124struct msn_switchboard *msn_sb_by_handle( struct im_connection *ic, const char *handle )
[b7d3cc34]125{
[0da65d5]126        struct msn_data *md = ic->proto_data;
[b7d3cc34]127        struct msn_switchboard *sb;
128        GSList *l;
129       
130        for( l = md->switchboards; l; l = l->next )
131        {
132                sb = l->data;
133                if( sb->who && strcmp( sb->who, handle ) == 0 )
134                        return( sb );
135        }
136       
137        return( NULL );
138}
139
[0da65d5]140struct msn_switchboard *msn_sb_by_chat( struct groupchat *c )
[b7d3cc34]141{
[0da65d5]142        struct msn_data *md = c->ic->proto_data;
[b7d3cc34]143        struct msn_switchboard *sb;
144        GSList *l;
145       
146        for( l = md->switchboards; l; l = l->next )
147        {
148                sb = l->data;
[fa29d093]149                if( sb->chat == c )
[b7d3cc34]150                        return( sb );
151        }
152       
153        return( NULL );
154}
155
[0da65d5]156struct msn_switchboard *msn_sb_spare( struct im_connection *ic )
[b7d3cc34]157{
[0da65d5]158        struct msn_data *md = ic->proto_data;
[b7d3cc34]159        struct msn_switchboard *sb;
160        GSList *l;
161       
162        for( l = md->switchboards; l; l = l->next )
163        {
164                sb = l->data;
165                if( !sb->who && !sb->chat )
166                        return( sb );
167        }
168       
169        return( NULL );
170}
171
172int msn_sb_sendmessage( struct msn_switchboard *sb, char *text )
173{
174        if( sb->ready )
175        {
[64768d4]176                char *buf;
[b7d3cc34]177                int i, j;
178               
[bd28e6a]179                /* Build the message. Convert LF to CR-LF for normal messages. */
[a2b99ec]180                if( strcmp( text, TYPING_NOTIFICATION_MESSAGE ) == 0 )
181                {
182                        i = strlen( MSN_TYPING_HEADERS ) + strlen( sb->ic->acc->user );
183                        buf = g_new0( char, i );
184                        i = g_snprintf( buf, i, MSN_TYPING_HEADERS, sb->ic->acc->user );
[1c3008a]185                }
[9c84617]186                else if( strcmp( text, NUDGE_MESSAGE ) == 0 )
187                {
188                        buf = g_strdup( MSN_NUDGE_HEADERS );
189                        i = strlen( buf );
190                }
[9bf2481]191                else if( strcmp( text, SB_KEEPALIVE_MESSAGE ) == 0 )
192                {
[9c84617]193                        buf = g_strdup( MSN_SB_KEEPALIVE_HEADERS );
[9bf2481]194                        i = strlen( buf );
195                }
[1c3008a]196                else if( strncmp( text, MSN_INVITE_HEADERS, sizeof( MSN_INVITE_HEADERS ) - 1 ) == 0 ) 
[a2b99ec]197                {
198                        buf = g_strdup( text );
199                        i = strlen( buf );
[1c3008a]200                }
201                else
[b7d3cc34]202                {
[46dca11]203                        buf = g_new0( char, sizeof( MSN_MESSAGE_HEADERS ) + strlen( text ) * 2 + 1 );
[b7d3cc34]204                        i = strlen( MSN_MESSAGE_HEADERS );
205                       
206                        strcpy( buf, MSN_MESSAGE_HEADERS );
207                        for( j = 0; text[j]; j ++ )
208                        {
209                                if( text[j] == '\n' )
210                                        buf[i++] = '\r';
211                               
212                                buf[i++] = text[j];
213                        }
214                }
215               
[bd28e6a]216                /* Build the final packet (MSG command + the message). */
[64768d4]217                if( msn_sb_write( sb, "MSG %d N %d\r\n%s", ++sb->trId, i, buf ) )
[b7d3cc34]218                {
[64768d4]219                        g_free( buf );
220                        return 1;
[b7d3cc34]221                }
222                else
223                {
[64768d4]224                        g_free( buf );
225                        return 0;
[b7d3cc34]226                }
227        }
228        else if( sb->who )
229        {
230                struct msn_message *m = g_new0( struct msn_message, 1 );
231               
232                m->who = g_strdup( "" );
233                m->text = g_strdup( text );
234                sb->msgq = g_slist_append( sb->msgq, m );
235               
236                return( 1 );
237        }
238        else
239        {
240                return( 0 );
241        }
242}
243
[0da65d5]244struct groupchat *msn_sb_to_chat( struct msn_switchboard *sb )
[b7d3cc34]245{
[0da65d5]246        struct im_connection *ic = sb->ic;
[e5abfd4]247        struct groupchat *c = NULL;
[b7d3cc34]248        char buf[1024];
249       
250        /* Create the groupchat structure. */
251        g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session );
[36577aa]252        if( sb->who )
[e5abfd4]253                c = bee_chat_by_title( ic->bee, ic, sb->who );
254        if( c && !msn_sb_by_chat( c ) )
255                sb->chat = c;
256        else
[36577aa]257                sb->chat = imcb_chat_new( ic, buf );
[b7d3cc34]258       
259        /* Populate the channel. */
[61ae52c]260        if( sb->who ) imcb_chat_add_buddy( sb->chat, sb->who );
261        imcb_chat_add_buddy( sb->chat, ic->acc->user );
[b7d3cc34]262       
263        /* And make sure the switchboard doesn't look like a regular chat anymore. */
264        if( sb->who )
265        {
266                g_free( sb->who );
267                sb->who = NULL;
268        }
[fa29d093]269       
270        return sb->chat;
[b7d3cc34]271}
272
273void msn_sb_destroy( struct msn_switchboard *sb )
274{
[0da65d5]275        struct im_connection *ic = sb->ic;
276        struct msn_data *md = ic->proto_data;
[b7d3cc34]277       
278        debug( "Destroying switchboard: %s", sb->who ? sb->who : sb->key ? sb->key : "" );
279       
[46dca11]280        msn_msgq_purge( ic, &sb->msgq );
[bb839e8]281        msn_sb_stop_keepalives( sb );
[b7d3cc34]282       
[8ba511d]283        if( sb->key ) g_free( sb->key );
284        if( sb->who ) g_free( sb->who );
285       
[b7d3cc34]286        if( sb->chat )
287        {
[e35d1a1]288                imcb_chat_free( sb->chat );
[b7d3cc34]289        }
290       
291        if( sb->handler )
292        {
293                if( sb->handler->rxq ) g_free( sb->handler->rxq );
294                if( sb->handler->cmd_text ) g_free( sb->handler->cmd_text );
295                g_free( sb->handler );
296        }
297       
[ba9edaa]298        if( sb->inp ) b_event_remove( sb->inp );
[b7d3cc34]299        closesocket( sb->fd );
300       
301        msn_switchboards = g_slist_remove( msn_switchboards, sb );
302        md->switchboards = g_slist_remove( md->switchboards, sb );
303        g_free( sb );
304}
305
[ba9edaa]306gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond )
[b7d3cc34]307{
308        struct msn_switchboard *sb = data;
[0da65d5]309        struct im_connection *ic;
[080c43a]310        struct msn_data *md;
[b7d3cc34]311        char buf[1024];
312       
313        /* Are we still alive? */
314        if( !g_slist_find( msn_switchboards, sb ) )
[ba9edaa]315                return FALSE;
[b7d3cc34]316       
[0da65d5]317        ic = sb->ic;
[080c43a]318        md = ic->proto_data;
[b7d3cc34]319       
320        if( source != sb->fd )
321        {
[46dca11]322                debug( "Error %d while connecting to switchboard server", 1 );
[b7d3cc34]323                msn_sb_destroy( sb );
[ba9edaa]324                return FALSE;
[b7d3cc34]325        }
326       
327        /* Prepare the callback */
328        sb->handler = g_new0( struct msn_handler_data, 1 );
329        sb->handler->fd = sb->fd;
330        sb->handler->rxq = g_new0( char, 1 );
331        sb->handler->data = sb;
332        sb->handler->exec_command = msn_sb_command;
333        sb->handler->exec_message = msn_sb_message;
334       
335        if( sb->session == MSN_SB_NEW )
[080c43a]336                g_snprintf( buf, sizeof( buf ), "USR %d %s;{%s} %s\r\n", ++sb->trId, ic->acc->user, md->uuid, sb->key );
[b7d3cc34]337        else
[080c43a]338                g_snprintf( buf, sizeof( buf ), "ANS %d %s;{%s} %s %d\r\n", ++sb->trId, ic->acc->user, md->uuid, sb->key, sb->session );
[b7d3cc34]339       
[64768d4]340        if( msn_sb_write( sb, "%s", buf ) )
[e046390]341                sb->inp = b_input_add( sb->fd, B_EV_IO_READ, msn_sb_callback, sb );
[b7d3cc34]342        else
[46dca11]343                debug( "Error %d while connecting to switchboard server", 2 );
[ba9edaa]344       
345        return FALSE;
[b7d3cc34]346}
347
[ba9edaa]348static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond )
[b7d3cc34]349{
350        struct msn_switchboard *sb = data;
[59f527b6]351        struct im_connection *ic = sb->ic;
352        struct msn_data *md = ic->proto_data;
[b7d3cc34]353       
[f8cb76d]354        if( msn_handler( sb->handler ) != -1 )
355                return TRUE;
356       
357        if( sb->msgq != NULL )
[b7d3cc34]358        {
[59f527b6]359                time_t now = time( NULL );
360               
361                if( now - md->first_sb_failure > 600 )
362                {
363                        /* It's not really the first one, but the start of this "series".
364                           With this, the warning below will be shown only if this happens
365                           at least three times in ten minutes. This algorithm isn't
366                           perfect, but for this purpose it will do. */
367                        md->first_sb_failure = now;
368                        md->sb_failures = 0;
369                }
370               
[46dca11]371                debug( "Error: Switchboard died" );
[59f527b6]372                if( ++ md->sb_failures >= 3 )
373                        imcb_log( ic, "Warning: Many switchboard failures on MSN connection. "
374                                      "There might be problems delivering your messages." );
375               
[f8cb76d]376                if( md->msgq == NULL )
[59f527b6]377                {
[f8cb76d]378                        md->msgq = sb->msgq;
379                }
380                else
381                {
382                        GSList *l;
[59f527b6]383                       
[f8cb76d]384                        for( l = md->msgq; l->next; l = l->next );
385                        l->next = sb->msgq;
[59f527b6]386                }
[f8cb76d]387                sb->msgq = NULL;
[59f527b6]388               
[f8cb76d]389                debug( "Moved queued messages back to the main queue, "
390                       "creating a new switchboard to retry." );
[64768d4]391                if( !msn_ns_write( ic, -1, "XFR %d SB\r\n", ++md->trId ) )
[f8cb76d]392                        return FALSE;
[59f527b6]393        }
[f8cb76d]394       
395        msn_sb_destroy( sb );
396        return FALSE;
[b7d3cc34]397}
398
[bae0617]399static int msn_sb_command( struct msn_handler_data *handler, char **cmd, int num_parts )
[b7d3cc34]400{
[bae0617]401        struct msn_switchboard *sb = handler->data;
[0da65d5]402        struct im_connection *ic = sb->ic;
[b7d3cc34]403       
404        if( !num_parts )
405        {
406                /* Hrrm... Empty command...? Ignore? */
407                return( 1 );
408        }
409       
410        if( strcmp( cmd[0], "XFR" ) == 0 )
411        {
[84b045d]412                imcb_error( ic, "Received an XFR from a switchboard server, unable to comply! This is likely to be a bug, please report it!" );
[c2fb3809]413                imc_logout( ic, TRUE );
[b7d3cc34]414                return( 0 );
415        }
416        else if( strcmp( cmd[0], "USR" ) == 0 )
417        {
[b46769d]418                if( num_parts < 5 )
[b7d3cc34]419                {
420                        msn_sb_destroy( sb );
421                        return( 0 );
422                }
423               
424                if( strcmp( cmd[2], "OK" ) != 0 )
425                {
426                        msn_sb_destroy( sb );
427                        return( 0 );
428                }
429               
430                if( sb->who )
[64768d4]431                        return msn_sb_write( sb, "CAL %d %s\r\n", ++sb->trId, sb->who );
[b7d3cc34]432                else
433                        debug( "Just created a switchboard, but I don't know what to do with it." );
434        }
435        else if( strcmp( cmd[0], "IRO" ) == 0 )
436        {
437                int num, tot;
438               
[b46769d]439                if( num_parts < 6 )
[b7d3cc34]440                {
441                        msn_sb_destroy( sb );
442                        return( 0 );
443                }
444               
445                num = atoi( cmd[2] );
446                tot = atoi( cmd[3] );
447               
448                if( tot <= 0 )
449                {
450                        msn_sb_destroy( sb );
451                        return( 0 );
452                }
453                else if( tot > 1 )
454                {
455                        char buf[1024];
456                       
[080c43a]457                        /* For as much as I understand this MPOP stuff now, a
458                           switchboard has two (or more) roster entries per
459                           participant. One "bare JID" and one JID;UUID. Ignore
460                           the latter. */
461                        if( !strchr( cmd[4], ';' ) )
[e9caacd]462                        {
463                                /* HACK: Since even 1:1 chats now have >2 participants
464                                   (ourselves included) it gets hard to tell them apart
465                                   from rooms. Let's hope this is enough: */
466                                if( sb->chat == NULL && num != tot )
467                                {
468                                        g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session );
469                                        sb->chat = imcb_chat_new( ic, buf );
470                                       
471                                        g_free( sb->who );
472                                        sb->who = NULL;
473                                }
474                               
475                                if( sb->chat )
476                                        imcb_chat_add_buddy( sb->chat, cmd[4] );
477                        }
[b7d3cc34]478                       
[e9caacd]479                        /* We have the full roster, start showing the channel to
480                           the user. */
481                        if( num == tot && sb->chat )
[b7d3cc34]482                        {
[61ae52c]483                                imcb_chat_add_buddy( sb->chat, ic->acc->user );
[b7d3cc34]484                        }
485                }
486        }
487        else if( strcmp( cmd[0], "ANS" ) == 0 )
488        {
[b46769d]489                if( num_parts < 3 )
[b7d3cc34]490                {
491                        msn_sb_destroy( sb );
492                        return( 0 );
493                }
494               
495                if( strcmp( cmd[2], "OK" ) != 0 )
496                {
497                        debug( "Switchboard server sent a negative ANS reply" );
498                        msn_sb_destroy( sb );
499                        return( 0 );
500                }
501               
502                sb->ready = 1;
[bb839e8]503               
504                msn_sb_start_keepalives( sb, FALSE );
[b7d3cc34]505        }
506        else if( strcmp( cmd[0], "CAL" ) == 0 )
507        {
[6b13103]508                if( num_parts < 4 || !g_ascii_isdigit( cmd[3][0] ) )
[b7d3cc34]509                {
510                        msn_sb_destroy( sb );
511                        return( 0 );
512                }
513               
514                sb->session = atoi( cmd[3] );
515        }
516        else if( strcmp( cmd[0], "JOI" ) == 0 )
517        {
[b46769d]518                if( num_parts < 3 )
[b7d3cc34]519                {
520                        msn_sb_destroy( sb );
521                        return( 0 );
522                }
523               
[080c43a]524                /* See IRO above. Handle "bare JIDs" only. */
525                if( strchr( cmd[1], ';' ) )
526                        return 1;
527               
[b7d3cc34]528                if( sb->who && g_strcasecmp( cmd[1], sb->who ) == 0 )
529                {
530                        /* The user we wanted to talk to is finally there, let's send the queued messages then. */
531                        struct msn_message *m;
532                        GSList *l;
533                        int st = 1;
534                       
535                        debug( "%s arrived in the switchboard session, now sending queued message(s)", cmd[1] );
536                       
537                        /* Without this, sendmessage() will put everything back on the queue... */
538                        sb->ready = 1;
539                       
540                        while( ( l = sb->msgq ) )
541                        {
542                                m = l->data;
543                                if( st )
544                                {
545                                        /* This hack is meant to convert a regular new chat into a groupchat */
546                                        if( strcmp( m->text, GROUPCHAT_SWITCHBOARD_MESSAGE ) == 0 )
547                                                msn_sb_to_chat( sb );
548                                        else
549                                                st = msn_sb_sendmessage( sb, m->text );
550                                }
551                                g_free( m->text );
552                                g_free( m->who );
553                                g_free( m );
554                               
555                                sb->msgq = g_slist_remove( sb->msgq, m );
556                        }
557                       
[bb839e8]558                        msn_sb_start_keepalives( sb, FALSE );
559                       
[b7d3cc34]560                        return( st );
561                }
[080c43a]562                else if( strcmp( cmd[1], ic->acc->user ) == 0 )
563                {
564                        /* Well, gee thanks. Thanks for letting me know I've arrived.. */
565                }
[b7d3cc34]566                else if( sb->who )
567                {
568                        debug( "Converting chat with %s to a groupchat because %s joined the session.", sb->who, cmd[1] );
569                       
570                        /* This SB is a one-to-one chat right now, but someone else is joining. */
571                        msn_sb_to_chat( sb );
572                       
[61ae52c]573                        imcb_chat_add_buddy( sb->chat, cmd[1] );
[b7d3cc34]574                }
575                else if( sb->chat )
576                {
[61ae52c]577                        imcb_chat_add_buddy( sb->chat, cmd[1] );
[b7d3cc34]578                        sb->ready = 1;
579                }
580                else
581                {
582                        /* PANIC! */
583                }
584        }
585        else if( strcmp( cmd[0], "MSG" ) == 0 )
586        {
[b46769d]587                if( num_parts < 4 )
[b7d3cc34]588                {
589                        msn_sb_destroy( sb );
590                        return( 0 );
591                }
592               
593                sb->handler->msglen = atoi( cmd[3] );
594               
595                if( sb->handler->msglen <= 0 )
596                {
597                        debug( "Received a corrupted message on the switchboard, the switchboard will be closed" );
598                        msn_sb_destroy( sb );
599                        return( 0 );
600                }
601        }
[3585c5a]602        else if( strcmp( cmd[0], "NAK" ) == 0 )
603        {
604                if( sb->who )
605                {
606                        imcb_log( ic, "The MSN servers could not deliver one of your messages to %s.", sb->who );
607                }
608                else
609                {
610                        imcb_log( ic, "The MSN servers could not deliver one of your groupchat messages to all participants." );
611                }
612        }
[b7d3cc34]613        else if( strcmp( cmd[0], "BYE" ) == 0 )
614        {
615                if( num_parts < 2 )
616                {
617                        msn_sb_destroy( sb );
618                        return( 0 );
619                }
620               
621                /* if( cmd[2] && *cmd[2] == '1' ) -=> Chat is being cleaned up because of idleness */
622               
623                if( sb->who )
624                {
[bb839e8]625                        msn_sb_stop_keepalives( sb );
626                       
[b7d3cc34]627                        /* This is a single-person chat, and the other person is leaving. */
628                        g_free( sb->who );
629                        sb->who = NULL;
630                        sb->ready = 0;
631                       
632                        debug( "Person %s left the one-to-one switchboard connection. Keeping it around as a spare...", cmd[1] );
633                       
634                        /* We could clean up the switchboard now, but keeping it around
635                           as a spare for a next conversation sounds more sane to me.
636                           The server will clean it up when it's idle for too long. */
637                }
[fe79de66]638                else if( sb->chat && !strchr( cmd[1], ';' ) )
[b7d3cc34]639                {
[61ae52c]640                        imcb_chat_remove_buddy( sb->chat, cmd[1], "" );
[b7d3cc34]641                }
642                else
643                {
644                        /* PANIC! */
645                }
646        }
[6b13103]647        else if( g_ascii_isdigit( cmd[0][0] ) )
[b7d3cc34]648        {
649                int num = atoi( cmd[0] );
[08995b0]650                const struct msn_status_code *err = msn_status_by_number( num );
[b7d3cc34]651               
[bc090f0]652                /* If the person is offline, send an offline message instead,
653                   and don't report an error. */
[e5a8118]654                if( num == 217 )
[bc676ac]655                        msn_ns_oim_send_queue( ic, &sb->msgq );
[bc090f0]656                else
657                        imcb_error( ic, "Error reported by switchboard server: %s", err->text );
[b7d3cc34]658               
659                if( err->flags & STATUS_SB_FATAL )
660                {
661                        msn_sb_destroy( sb );
[6048744]662                        return 0;
[b7d3cc34]663                }
[6048744]664                else if( err->flags & STATUS_FATAL )
[b7d3cc34]665                {
[c2fb3809]666                        imc_logout( ic, TRUE );
[6048744]667                        return 0;
[b7d3cc34]668                }
[6048744]669                else if( err->flags & STATUS_SB_IM_SPARE )
[3b9390b]670                {
671                        if( sb->who )
672                        {
673                                /* Apparently some invitation failed. We might want to use this
674                                   board later, so keep it as a spare. */
675                                g_free( sb->who );
676                                sb->who = NULL;
677                               
678                                /* Also clear the msgq, otherwise someone else might get them. */
[46dca11]679                                msn_msgq_purge( ic, &sb->msgq );
[3b9390b]680                        }
[6048744]681                       
682                        /* Do NOT return 0 here, we want to keep this sb. */
[3b9390b]683                }
[b7d3cc34]684        }
685        else
686        {
[8ff0a61]687                /* debug( "Received unknown command from switchboard server: %s", cmd[0] ); */
[b7d3cc34]688        }
689       
690        return( 1 );
691}
692
[bae0617]693static int msn_sb_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts )
[b7d3cc34]694{
[bae0617]695        struct msn_switchboard *sb = handler->data;
[0da65d5]696        struct im_connection *ic = sb->ic;
[b7d3cc34]697        char *body;
698       
699        if( !num_parts )
700                return( 1 );
701       
702        if( ( body = strstr( msg, "\r\n\r\n" ) ) )
703                body += 4;
704       
705        if( strcmp( cmd[0], "MSG" ) == 0 )
706        {
[9b0ad7e]707                char *ct = get_rfc822_header( msg, "Content-Type:", msglen );
[b7d3cc34]708               
709                if( !ct )
710                        return( 1 );
711               
712                if( g_strncasecmp( ct, "text/plain", 10 ) == 0 )
713                {
714                        g_free( ct );
715                       
716                        if( !body )
717                                return( 1 );
718                       
719                        if( sb->who )
720                        {
[9624fdf]721                                imcb_buddy_msg( ic, cmd[1], body, 0, 0 );
[b7d3cc34]722                        }
723                        else if( sb->chat )
724                        {
[61ae52c]725                                imcb_chat_msg( sb->chat, cmd[1], body, 0, 0 );
[b7d3cc34]726                        }
727                        else
728                        {
729                                /* PANIC! */
730                        }
731                }
[17a6ee9]732#if 0
733                // Disable MSN ft support for now.
[b7d3cc34]734                else if( g_strncasecmp( ct, "text/x-msmsgsinvite", 19 ) == 0 )
735                {
[9b0ad7e]736                        char *command = get_rfc822_header( body, "Invitation-Command:", blen );
737                        char *cookie = get_rfc822_header( body, "Invitation-Cookie:", blen );
[a2b99ec]738                        unsigned int icookie;
[b7d3cc34]739                       
740                        g_free( ct );
741                       
[a2b99ec]742                        /* Every invite should have both a Command and Cookie header */
743                        if( !command || !cookie ) {
744                                g_free( command );
745                                g_free( cookie );
746                                imcb_log( ic, "Warning: No command or cookie from %s", sb->who );
747                                return 1;
[b7d3cc34]748                        }
749                       
[a2b99ec]750                        icookie = strtoul( cookie, NULL, 10 );
751                        g_free( cookie );
[b7d3cc34]752                       
[a2b99ec]753                        if( g_strncasecmp( command, "INVITE", 6 ) == 0 ) {
754                                msn_invitation_invite( sb, cmd[1], icookie, body, blen );
755                        } else if( g_strncasecmp( command, "ACCEPT", 6 ) == 0 ) {
756                                msn_invitation_accept( sb, cmd[1], icookie, body, blen );
757                        } else if( g_strncasecmp( command, "CANCEL", 6 ) == 0 ) {
758                                msn_invitation_cancel( sb, cmd[1], icookie, body, blen );
759                        } else {
760                                imcb_log( ic, "Warning: Received invalid invitation with "
761                                                "command %s from %s", command, sb->who );
[b7d3cc34]762                        }
[a2b99ec]763                       
764                        g_free( command );
765                }
[17a6ee9]766#endif
[a2b99ec]767                else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 ) 
768                {
[9b1d2d6]769                        /* Not currently implemented. Don't warn about it since
770                           this seems to be used for avatars now. */
[a2b99ec]771                        g_free( ct );
[b7d3cc34]772                }
773                else if( g_strncasecmp( ct, "text/x-msmsgscontrol", 20 ) == 0 )
774                {
[9b0ad7e]775                        char *who = get_rfc822_header( msg, "TypingUser:", msglen );
[b7d3cc34]776                       
777                        if( who )
778                        {
[9624fdf]779                                imcb_buddy_typing( ic, who, OPT_TYPING );
[b7d3cc34]780                                g_free( who );
781                        }
782                       
783                        g_free( ct );
784                }
785                else
786                {
787                        g_free( ct );
788                }
789        }
790       
791        return( 1 );
792}
[9bf2481]793
[bb839e8]794static gboolean msn_sb_keepalive( gpointer data, gint source, b_input_condition cond )
[9bf2481]795{
796        struct msn_switchboard *sb = data;
797        return sb->ready && msn_sb_sendmessage( sb, SB_KEEPALIVE_MESSAGE );
798}
[bb839e8]799
800void msn_sb_start_keepalives( struct msn_switchboard *sb, gboolean initial )
801{
[f924563]802        bee_user_t *bu;
[bb839e8]803       
804        if( sb && sb->who && sb->keepalive == 0 &&
[f924563]805            ( bu = bee_user_by_handle( sb->ic->bee, sb->ic, sb->who ) ) &&
806            !( bu->flags & BEE_USER_ONLINE ) &&
[bb839e8]807            set_getbool( &sb->ic->acc->set, "switchboard_keepalives" ) )
808        {
809                if( initial )
810                        msn_sb_keepalive( sb, 0, 0 );
811               
812                sb->keepalive = b_timeout_add( 20000, msn_sb_keepalive, sb );
813        }
814}
815
816void msn_sb_stop_keepalives( struct msn_switchboard *sb )
817{
818        if( sb && sb->keepalive > 0 )
819        {
820                b_event_remove( sb->keepalive );
821                sb->keepalive = 0;
822        }
823}
Note: See TracBrowser for help on using the repository browser.