source: protocols/msn/sb.c @ 9c84617

Last change on this file since 9c84617 was 9c84617, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-12-13T00:42:58Z

Silently adding /CTCP NUDGE support for MSN contacts.

  • Property mode set to 100644
File size: 18.8 KB
RevLine 
[b7d3cc34]1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
[4e4af1b]4  * Copyright 2002-2010 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;
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 <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" ) )
[64768d4]49                fprintf( stderr, "->SB%d:%s", 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
[0da65d5]124struct msn_switchboard *msn_sb_by_handle( struct im_connection *ic, 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;
[b7d3cc34]310        struct msn_data *md;
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;
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 )
[c2fb3809]336                g_snprintf( buf, sizeof( buf ), "USR %d %s %s\r\n", ++sb->trId, ic->acc->user, sb->key );
[b7d3cc34]337        else
[c2fb3809]338                g_snprintf( buf, sizeof( buf ), "ANS %d %s %s %d\r\n", ++sb->trId, ic->acc->user, 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                       
457                        if( num == 1 )
458                        {
459                                g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session );
[61ae52c]460                                sb->chat = imcb_chat_new( ic, buf );
[b7d3cc34]461                               
462                                g_free( sb->who );
463                                sb->who = NULL;
464                        }
465                       
[61ae52c]466                        imcb_chat_add_buddy( sb->chat, cmd[4] );
[b7d3cc34]467                       
468                        if( num == tot )
469                        {
[61ae52c]470                                imcb_chat_add_buddy( sb->chat, ic->acc->user );
[b7d3cc34]471                        }
472                }
473        }
474        else if( strcmp( cmd[0], "ANS" ) == 0 )
475        {
[b46769d]476                if( num_parts < 3 )
[b7d3cc34]477                {
478                        msn_sb_destroy( sb );
479                        return( 0 );
480                }
481               
482                if( strcmp( cmd[2], "OK" ) != 0 )
483                {
484                        debug( "Switchboard server sent a negative ANS reply" );
485                        msn_sb_destroy( sb );
486                        return( 0 );
487                }
488               
489                sb->ready = 1;
[bb839e8]490               
491                msn_sb_start_keepalives( sb, FALSE );
[b7d3cc34]492        }
493        else if( strcmp( cmd[0], "CAL" ) == 0 )
494        {
[b46769d]495                if( num_parts < 4 || !isdigit( cmd[3][0] ) )
[b7d3cc34]496                {
497                        msn_sb_destroy( sb );
498                        return( 0 );
499                }
500               
501                sb->session = atoi( cmd[3] );
502        }
503        else if( strcmp( cmd[0], "JOI" ) == 0 )
504        {
[b46769d]505                if( num_parts < 3 )
[b7d3cc34]506                {
507                        msn_sb_destroy( sb );
508                        return( 0 );
509                }
510               
511                if( sb->who && g_strcasecmp( cmd[1], sb->who ) == 0 )
512                {
513                        /* The user we wanted to talk to is finally there, let's send the queued messages then. */
514                        struct msn_message *m;
515                        GSList *l;
516                        int st = 1;
517                       
518                        debug( "%s arrived in the switchboard session, now sending queued message(s)", cmd[1] );
519                       
520                        /* Without this, sendmessage() will put everything back on the queue... */
521                        sb->ready = 1;
522                       
523                        while( ( l = sb->msgq ) )
524                        {
525                                m = l->data;
526                                if( st )
527                                {
528                                        /* This hack is meant to convert a regular new chat into a groupchat */
529                                        if( strcmp( m->text, GROUPCHAT_SWITCHBOARD_MESSAGE ) == 0 )
530                                                msn_sb_to_chat( sb );
531                                        else
532                                                st = msn_sb_sendmessage( sb, m->text );
533                                }
534                                g_free( m->text );
535                                g_free( m->who );
536                                g_free( m );
537                               
538                                sb->msgq = g_slist_remove( sb->msgq, m );
539                        }
540                       
[bb839e8]541                        msn_sb_start_keepalives( sb, FALSE );
542                       
[b7d3cc34]543                        return( st );
544                }
545                else if( sb->who )
546                {
547                        debug( "Converting chat with %s to a groupchat because %s joined the session.", sb->who, cmd[1] );
548                       
549                        /* This SB is a one-to-one chat right now, but someone else is joining. */
550                        msn_sb_to_chat( sb );
551                       
[61ae52c]552                        imcb_chat_add_buddy( sb->chat, cmd[1] );
[b7d3cc34]553                }
554                else if( sb->chat )
555                {
[61ae52c]556                        imcb_chat_add_buddy( sb->chat, cmd[1] );
[b7d3cc34]557                        sb->ready = 1;
558                }
559                else
560                {
561                        /* PANIC! */
562                }
563        }
564        else if( strcmp( cmd[0], "MSG" ) == 0 )
565        {
[b46769d]566                if( num_parts < 4 )
[b7d3cc34]567                {
568                        msn_sb_destroy( sb );
569                        return( 0 );
570                }
571               
572                sb->handler->msglen = atoi( cmd[3] );
573               
574                if( sb->handler->msglen <= 0 )
575                {
576                        debug( "Received a corrupted message on the switchboard, the switchboard will be closed" );
577                        msn_sb_destroy( sb );
578                        return( 0 );
579                }
580        }
[3585c5a]581        else if( strcmp( cmd[0], "NAK" ) == 0 )
582        {
583                if( sb->who )
584                {
585                        imcb_log( ic, "The MSN servers could not deliver one of your messages to %s.", sb->who );
586                }
587                else
588                {
589                        imcb_log( ic, "The MSN servers could not deliver one of your groupchat messages to all participants." );
590                }
591        }
[b7d3cc34]592        else if( strcmp( cmd[0], "BYE" ) == 0 )
593        {
594                if( num_parts < 2 )
595                {
596                        msn_sb_destroy( sb );
597                        return( 0 );
598                }
599               
600                /* if( cmd[2] && *cmd[2] == '1' ) -=> Chat is being cleaned up because of idleness */
601               
602                if( sb->who )
603                {
[bb839e8]604                        msn_sb_stop_keepalives( sb );
605                       
[b7d3cc34]606                        /* This is a single-person chat, and the other person is leaving. */
607                        g_free( sb->who );
608                        sb->who = NULL;
609                        sb->ready = 0;
610                       
611                        debug( "Person %s left the one-to-one switchboard connection. Keeping it around as a spare...", cmd[1] );
612                       
613                        /* We could clean up the switchboard now, but keeping it around
614                           as a spare for a next conversation sounds more sane to me.
615                           The server will clean it up when it's idle for too long. */
616                }
617                else if( sb->chat )
618                {
[61ae52c]619                        imcb_chat_remove_buddy( sb->chat, cmd[1], "" );
[b7d3cc34]620                }
621                else
622                {
623                        /* PANIC! */
624                }
625        }
626        else if( isdigit( cmd[0][0] ) )
627        {
628                int num = atoi( cmd[0] );
[08995b0]629                const struct msn_status_code *err = msn_status_by_number( num );
[b7d3cc34]630               
[bc090f0]631                /* If the person is offline, send an offline message instead,
632                   and don't report an error. */
[e5a8118]633                if( num == 217 )
[bc090f0]634                        msn_soap_oim_send_queue( ic, &sb->msgq );
635                else
636                        imcb_error( ic, "Error reported by switchboard server: %s", err->text );
[b7d3cc34]637               
638                if( err->flags & STATUS_SB_FATAL )
639                {
640                        msn_sb_destroy( sb );
[6048744]641                        return 0;
[b7d3cc34]642                }
[6048744]643                else if( err->flags & STATUS_FATAL )
[b7d3cc34]644                {
[c2fb3809]645                        imc_logout( ic, TRUE );
[6048744]646                        return 0;
[b7d3cc34]647                }
[6048744]648                else if( err->flags & STATUS_SB_IM_SPARE )
[3b9390b]649                {
650                        if( sb->who )
651                        {
652                                /* Apparently some invitation failed. We might want to use this
653                                   board later, so keep it as a spare. */
654                                g_free( sb->who );
655                                sb->who = NULL;
656                               
657                                /* Also clear the msgq, otherwise someone else might get them. */
[46dca11]658                                msn_msgq_purge( ic, &sb->msgq );
[3b9390b]659                        }
[6048744]660                       
661                        /* Do NOT return 0 here, we want to keep this sb. */
[3b9390b]662                }
[b7d3cc34]663        }
664        else
665        {
[8ff0a61]666                /* debug( "Received unknown command from switchboard server: %s", cmd[0] ); */
[b7d3cc34]667        }
668       
669        return( 1 );
670}
671
[bae0617]672static int msn_sb_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts )
[b7d3cc34]673{
[bae0617]674        struct msn_switchboard *sb = handler->data;
[0da65d5]675        struct im_connection *ic = sb->ic;
[b7d3cc34]676        char *body;
677        int blen = 0;
678       
679        if( !num_parts )
680                return( 1 );
681       
682        if( ( body = strstr( msg, "\r\n\r\n" ) ) )
683        {
684                body += 4;
685                blen = msglen - ( body - msg );
686        }
687       
688        if( strcmp( cmd[0], "MSG" ) == 0 )
689        {
690                char *ct = msn_findheader( msg, "Content-Type:", msglen );
691               
692                if( !ct )
693                        return( 1 );
694               
695                if( g_strncasecmp( ct, "text/plain", 10 ) == 0 )
696                {
697                        g_free( ct );
698                       
699                        if( !body )
700                                return( 1 );
701                       
702                        if( sb->who )
703                        {
[9624fdf]704                                imcb_buddy_msg( ic, cmd[1], body, 0, 0 );
[b7d3cc34]705                        }
706                        else if( sb->chat )
707                        {
[61ae52c]708                                imcb_chat_msg( sb->chat, cmd[1], body, 0, 0 );
[b7d3cc34]709                        }
710                        else
711                        {
712                                /* PANIC! */
713                        }
714                }
[17a6ee9]715#if 0
716                // Disable MSN ft support for now.
[b7d3cc34]717                else if( g_strncasecmp( ct, "text/x-msmsgsinvite", 19 ) == 0 )
718                {
[a2b99ec]719                        char *command = msn_findheader( body, "Invitation-Command:", blen );
720                        char *cookie = msn_findheader( body, "Invitation-Cookie:", blen );
721                        unsigned int icookie;
[b7d3cc34]722                       
723                        g_free( ct );
724                       
[a2b99ec]725                        /* Every invite should have both a Command and Cookie header */
726                        if( !command || !cookie ) {
727                                g_free( command );
728                                g_free( cookie );
729                                imcb_log( ic, "Warning: No command or cookie from %s", sb->who );
730                                return 1;
[b7d3cc34]731                        }
732                       
[a2b99ec]733                        icookie = strtoul( cookie, NULL, 10 );
734                        g_free( cookie );
[b7d3cc34]735                       
[a2b99ec]736                        if( g_strncasecmp( command, "INVITE", 6 ) == 0 ) {
737                                msn_invitation_invite( sb, cmd[1], icookie, body, blen );
738                        } else if( g_strncasecmp( command, "ACCEPT", 6 ) == 0 ) {
739                                msn_invitation_accept( sb, cmd[1], icookie, body, blen );
740                        } else if( g_strncasecmp( command, "CANCEL", 6 ) == 0 ) {
741                                msn_invitation_cancel( sb, cmd[1], icookie, body, blen );
742                        } else {
743                                imcb_log( ic, "Warning: Received invalid invitation with "
744                                                "command %s from %s", command, sb->who );
[b7d3cc34]745                        }
[a2b99ec]746                       
747                        g_free( command );
748                }
[17a6ee9]749#endif
[a2b99ec]750                else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 ) 
751                {
[9b1d2d6]752                        /* Not currently implemented. Don't warn about it since
753                           this seems to be used for avatars now. */
[a2b99ec]754                        g_free( ct );
[b7d3cc34]755                }
756                else if( g_strncasecmp( ct, "text/x-msmsgscontrol", 20 ) == 0 )
757                {
758                        char *who = msn_findheader( msg, "TypingUser:", msglen );
759                       
760                        if( who )
761                        {
[9624fdf]762                                imcb_buddy_typing( ic, who, OPT_TYPING );
[b7d3cc34]763                                g_free( who );
764                        }
765                       
766                        g_free( ct );
767                }
768                else
769                {
770                        g_free( ct );
771                }
772        }
773       
774        return( 1 );
775}
[9bf2481]776
[bb839e8]777static gboolean msn_sb_keepalive( gpointer data, gint source, b_input_condition cond )
[9bf2481]778{
779        struct msn_switchboard *sb = data;
780        return sb->ready && msn_sb_sendmessage( sb, SB_KEEPALIVE_MESSAGE );
781}
[bb839e8]782
783void msn_sb_start_keepalives( struct msn_switchboard *sb, gboolean initial )
784{
[f924563]785        bee_user_t *bu;
[bb839e8]786       
787        if( sb && sb->who && sb->keepalive == 0 &&
[f924563]788            ( bu = bee_user_by_handle( sb->ic->bee, sb->ic, sb->who ) ) &&
789            !( bu->flags & BEE_USER_ONLINE ) &&
[bb839e8]790            set_getbool( &sb->ic->acc->set, "switchboard_keepalives" ) )
791        {
792                if( initial )
793                        msn_sb_keepalive( sb, 0, 0 );
794               
795                sb->keepalive = b_timeout_add( 20000, msn_sb_keepalive, sb );
796        }
797}
798
799void msn_sb_stop_keepalives( struct msn_switchboard *sb )
800{
801        if( sb && sb->keepalive > 0 )
802        {
803                b_event_remove( sb->keepalive );
804                sb->keepalive = 0;
805        }
806}
Note: See TracBrowser for help on using the repository browser.