source: protocols/msn/sb.c @ 4c73ba62

Last change on this file since 4c73ba62 was dcf155d, checked in by Wilmer van der Gaast <wilmer@…>, at 2012-02-11T17:26:41Z

Drop dead support for MSN offline messages (that SOAP server isn't even in
DNS anymore). Bug #874 for adding support for the new (much simpler, for a
change) way.

  • 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" ) )
[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
[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        char buf[1024];
311       
312        /* Are we still alive? */
313        if( !g_slist_find( msn_switchboards, sb ) )
[ba9edaa]314                return FALSE;
[b7d3cc34]315       
[0da65d5]316        ic = sb->ic;
[b7d3cc34]317       
318        if( source != sb->fd )
319        {
[46dca11]320                debug( "Error %d while connecting to switchboard server", 1 );
[b7d3cc34]321                msn_sb_destroy( sb );
[ba9edaa]322                return FALSE;
[b7d3cc34]323        }
324       
325        /* Prepare the callback */
326        sb->handler = g_new0( struct msn_handler_data, 1 );
327        sb->handler->fd = sb->fd;
328        sb->handler->rxq = g_new0( char, 1 );
329        sb->handler->data = sb;
330        sb->handler->exec_command = msn_sb_command;
331        sb->handler->exec_message = msn_sb_message;
332       
333        if( sb->session == MSN_SB_NEW )
[c2fb3809]334                g_snprintf( buf, sizeof( buf ), "USR %d %s %s\r\n", ++sb->trId, ic->acc->user, sb->key );
[b7d3cc34]335        else
[c2fb3809]336                g_snprintf( buf, sizeof( buf ), "ANS %d %s %s %d\r\n", ++sb->trId, ic->acc->user, sb->key, sb->session );
[b7d3cc34]337       
[64768d4]338        if( msn_sb_write( sb, "%s", buf ) )
[e046390]339                sb->inp = b_input_add( sb->fd, B_EV_IO_READ, msn_sb_callback, sb );
[b7d3cc34]340        else
[46dca11]341                debug( "Error %d while connecting to switchboard server", 2 );
[ba9edaa]342       
343        return FALSE;
[b7d3cc34]344}
345
[ba9edaa]346static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond )
[b7d3cc34]347{
348        struct msn_switchboard *sb = data;
[59f527b6]349        struct im_connection *ic = sb->ic;
350        struct msn_data *md = ic->proto_data;
[b7d3cc34]351       
[f8cb76d]352        if( msn_handler( sb->handler ) != -1 )
353                return TRUE;
354       
355        if( sb->msgq != NULL )
[b7d3cc34]356        {
[59f527b6]357                time_t now = time( NULL );
358               
359                if( now - md->first_sb_failure > 600 )
360                {
361                        /* It's not really the first one, but the start of this "series".
362                           With this, the warning below will be shown only if this happens
363                           at least three times in ten minutes. This algorithm isn't
364                           perfect, but for this purpose it will do. */
365                        md->first_sb_failure = now;
366                        md->sb_failures = 0;
367                }
368               
[46dca11]369                debug( "Error: Switchboard died" );
[59f527b6]370                if( ++ md->sb_failures >= 3 )
371                        imcb_log( ic, "Warning: Many switchboard failures on MSN connection. "
372                                      "There might be problems delivering your messages." );
373               
[f8cb76d]374                if( md->msgq == NULL )
[59f527b6]375                {
[f8cb76d]376                        md->msgq = sb->msgq;
377                }
378                else
379                {
380                        GSList *l;
[59f527b6]381                       
[f8cb76d]382                        for( l = md->msgq; l->next; l = l->next );
383                        l->next = sb->msgq;
[59f527b6]384                }
[f8cb76d]385                sb->msgq = NULL;
[59f527b6]386               
[f8cb76d]387                debug( "Moved queued messages back to the main queue, "
388                       "creating a new switchboard to retry." );
[64768d4]389                if( !msn_ns_write( ic, -1, "XFR %d SB\r\n", ++md->trId ) )
[f8cb76d]390                        return FALSE;
[59f527b6]391        }
[f8cb76d]392       
393        msn_sb_destroy( sb );
394        return FALSE;
[b7d3cc34]395}
396
[bae0617]397static int msn_sb_command( struct msn_handler_data *handler, char **cmd, int num_parts )
[b7d3cc34]398{
[bae0617]399        struct msn_switchboard *sb = handler->data;
[0da65d5]400        struct im_connection *ic = sb->ic;
[b7d3cc34]401       
402        if( !num_parts )
403        {
404                /* Hrrm... Empty command...? Ignore? */
405                return( 1 );
406        }
407       
408        if( strcmp( cmd[0], "XFR" ) == 0 )
409        {
[84b045d]410                imcb_error( ic, "Received an XFR from a switchboard server, unable to comply! This is likely to be a bug, please report it!" );
[c2fb3809]411                imc_logout( ic, TRUE );
[b7d3cc34]412                return( 0 );
413        }
414        else if( strcmp( cmd[0], "USR" ) == 0 )
415        {
[b46769d]416                if( num_parts < 5 )
[b7d3cc34]417                {
418                        msn_sb_destroy( sb );
419                        return( 0 );
420                }
421               
422                if( strcmp( cmd[2], "OK" ) != 0 )
423                {
424                        msn_sb_destroy( sb );
425                        return( 0 );
426                }
427               
428                if( sb->who )
[64768d4]429                        return msn_sb_write( sb, "CAL %d %s\r\n", ++sb->trId, sb->who );
[b7d3cc34]430                else
431                        debug( "Just created a switchboard, but I don't know what to do with it." );
432        }
433        else if( strcmp( cmd[0], "IRO" ) == 0 )
434        {
435                int num, tot;
436               
[b46769d]437                if( num_parts < 6 )
[b7d3cc34]438                {
439                        msn_sb_destroy( sb );
440                        return( 0 );
441                }
442               
443                num = atoi( cmd[2] );
444                tot = atoi( cmd[3] );
445               
446                if( tot <= 0 )
447                {
448                        msn_sb_destroy( sb );
449                        return( 0 );
450                }
451                else if( tot > 1 )
452                {
453                        char buf[1024];
454                       
455                        if( num == 1 )
456                        {
457                                g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session );
[61ae52c]458                                sb->chat = imcb_chat_new( ic, buf );
[b7d3cc34]459                               
460                                g_free( sb->who );
461                                sb->who = NULL;
462                        }
463                       
[61ae52c]464                        imcb_chat_add_buddy( sb->chat, cmd[4] );
[b7d3cc34]465                       
466                        if( num == tot )
467                        {
[61ae52c]468                                imcb_chat_add_buddy( sb->chat, ic->acc->user );
[b7d3cc34]469                        }
470                }
471        }
472        else if( strcmp( cmd[0], "ANS" ) == 0 )
473        {
[b46769d]474                if( num_parts < 3 )
[b7d3cc34]475                {
476                        msn_sb_destroy( sb );
477                        return( 0 );
478                }
479               
480                if( strcmp( cmd[2], "OK" ) != 0 )
481                {
482                        debug( "Switchboard server sent a negative ANS reply" );
483                        msn_sb_destroy( sb );
484                        return( 0 );
485                }
486               
487                sb->ready = 1;
[bb839e8]488               
489                msn_sb_start_keepalives( sb, FALSE );
[b7d3cc34]490        }
491        else if( strcmp( cmd[0], "CAL" ) == 0 )
492        {
[b46769d]493                if( num_parts < 4 || !isdigit( cmd[3][0] ) )
[b7d3cc34]494                {
495                        msn_sb_destroy( sb );
496                        return( 0 );
497                }
498               
499                sb->session = atoi( cmd[3] );
500        }
501        else if( strcmp( cmd[0], "JOI" ) == 0 )
502        {
[b46769d]503                if( num_parts < 3 )
[b7d3cc34]504                {
505                        msn_sb_destroy( sb );
506                        return( 0 );
507                }
508               
509                if( sb->who && g_strcasecmp( cmd[1], sb->who ) == 0 )
510                {
511                        /* The user we wanted to talk to is finally there, let's send the queued messages then. */
512                        struct msn_message *m;
513                        GSList *l;
514                        int st = 1;
515                       
516                        debug( "%s arrived in the switchboard session, now sending queued message(s)", cmd[1] );
517                       
518                        /* Without this, sendmessage() will put everything back on the queue... */
519                        sb->ready = 1;
520                       
521                        while( ( l = sb->msgq ) )
522                        {
523                                m = l->data;
524                                if( st )
525                                {
526                                        /* This hack is meant to convert a regular new chat into a groupchat */
527                                        if( strcmp( m->text, GROUPCHAT_SWITCHBOARD_MESSAGE ) == 0 )
528                                                msn_sb_to_chat( sb );
529                                        else
530                                                st = msn_sb_sendmessage( sb, m->text );
531                                }
532                                g_free( m->text );
533                                g_free( m->who );
534                                g_free( m );
535                               
536                                sb->msgq = g_slist_remove( sb->msgq, m );
537                        }
538                       
[bb839e8]539                        msn_sb_start_keepalives( sb, FALSE );
540                       
[b7d3cc34]541                        return( st );
542                }
543                else if( sb->who )
544                {
545                        debug( "Converting chat with %s to a groupchat because %s joined the session.", sb->who, cmd[1] );
546                       
547                        /* This SB is a one-to-one chat right now, but someone else is joining. */
548                        msn_sb_to_chat( sb );
549                       
[61ae52c]550                        imcb_chat_add_buddy( sb->chat, cmd[1] );
[b7d3cc34]551                }
552                else if( sb->chat )
553                {
[61ae52c]554                        imcb_chat_add_buddy( sb->chat, cmd[1] );
[b7d3cc34]555                        sb->ready = 1;
556                }
557                else
558                {
559                        /* PANIC! */
560                }
561        }
562        else if( strcmp( cmd[0], "MSG" ) == 0 )
563        {
[b46769d]564                if( num_parts < 4 )
[b7d3cc34]565                {
566                        msn_sb_destroy( sb );
567                        return( 0 );
568                }
569               
570                sb->handler->msglen = atoi( cmd[3] );
571               
572                if( sb->handler->msglen <= 0 )
573                {
574                        debug( "Received a corrupted message on the switchboard, the switchboard will be closed" );
575                        msn_sb_destroy( sb );
576                        return( 0 );
577                }
578        }
[3585c5a]579        else if( strcmp( cmd[0], "NAK" ) == 0 )
580        {
581                if( sb->who )
582                {
583                        imcb_log( ic, "The MSN servers could not deliver one of your messages to %s.", sb->who );
584                }
585                else
586                {
587                        imcb_log( ic, "The MSN servers could not deliver one of your groupchat messages to all participants." );
588                }
589        }
[b7d3cc34]590        else if( strcmp( cmd[0], "BYE" ) == 0 )
591        {
592                if( num_parts < 2 )
593                {
594                        msn_sb_destroy( sb );
595                        return( 0 );
596                }
597               
598                /* if( cmd[2] && *cmd[2] == '1' ) -=> Chat is being cleaned up because of idleness */
599               
600                if( sb->who )
601                {
[bb839e8]602                        msn_sb_stop_keepalives( sb );
603                       
[b7d3cc34]604                        /* This is a single-person chat, and the other person is leaving. */
605                        g_free( sb->who );
606                        sb->who = NULL;
607                        sb->ready = 0;
608                       
609                        debug( "Person %s left the one-to-one switchboard connection. Keeping it around as a spare...", cmd[1] );
610                       
611                        /* We could clean up the switchboard now, but keeping it around
612                           as a spare for a next conversation sounds more sane to me.
613                           The server will clean it up when it's idle for too long. */
614                }
615                else if( sb->chat )
616                {
[61ae52c]617                        imcb_chat_remove_buddy( sb->chat, cmd[1], "" );
[b7d3cc34]618                }
619                else
620                {
621                        /* PANIC! */
622                }
623        }
624        else if( isdigit( cmd[0][0] ) )
625        {
626                int num = atoi( cmd[0] );
[08995b0]627                const struct msn_status_code *err = msn_status_by_number( num );
[b7d3cc34]628               
[bc090f0]629                /* If the person is offline, send an offline message instead,
630                   and don't report an error. */
[dcf155d]631                /* TODO: Support for OIMs that works. (#874) */
632                /*
[e5a8118]633                if( num == 217 )
[bc090f0]634                        msn_soap_oim_send_queue( ic, &sb->msgq );
635                else
[dcf155d]636                */
[bc090f0]637                        imcb_error( ic, "Error reported by switchboard server: %s", err->text );
[b7d3cc34]638               
639                if( err->flags & STATUS_SB_FATAL )
640                {
641                        msn_sb_destroy( sb );
[6048744]642                        return 0;
[b7d3cc34]643                }
[6048744]644                else if( err->flags & STATUS_FATAL )
[b7d3cc34]645                {
[c2fb3809]646                        imc_logout( ic, TRUE );
[6048744]647                        return 0;
[b7d3cc34]648                }
[6048744]649                else if( err->flags & STATUS_SB_IM_SPARE )
[3b9390b]650                {
651                        if( sb->who )
652                        {
653                                /* Apparently some invitation failed. We might want to use this
654                                   board later, so keep it as a spare. */
655                                g_free( sb->who );
656                                sb->who = NULL;
657                               
658                                /* Also clear the msgq, otherwise someone else might get them. */
[46dca11]659                                msn_msgq_purge( ic, &sb->msgq );
[3b9390b]660                        }
[6048744]661                       
662                        /* Do NOT return 0 here, we want to keep this sb. */
[3b9390b]663                }
[b7d3cc34]664        }
665        else
666        {
[8ff0a61]667                /* debug( "Received unknown command from switchboard server: %s", cmd[0] ); */
[b7d3cc34]668        }
669       
670        return( 1 );
671}
672
[bae0617]673static int msn_sb_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts )
[b7d3cc34]674{
[bae0617]675        struct msn_switchboard *sb = handler->data;
[0da65d5]676        struct im_connection *ic = sb->ic;
[b7d3cc34]677        char *body;
678       
679        if( !num_parts )
680                return( 1 );
681       
682        if( ( body = strstr( msg, "\r\n\r\n" ) ) )
683                body += 4;
684       
685        if( strcmp( cmd[0], "MSG" ) == 0 )
686        {
[9b0ad7e]687                char *ct = get_rfc822_header( msg, "Content-Type:", msglen );
[b7d3cc34]688               
689                if( !ct )
690                        return( 1 );
691               
692                if( g_strncasecmp( ct, "text/plain", 10 ) == 0 )
693                {
694                        g_free( ct );
695                       
696                        if( !body )
697                                return( 1 );
698                       
699                        if( sb->who )
700                        {
[9624fdf]701                                imcb_buddy_msg( ic, cmd[1], body, 0, 0 );
[b7d3cc34]702                        }
703                        else if( sb->chat )
704                        {
[61ae52c]705                                imcb_chat_msg( sb->chat, cmd[1], body, 0, 0 );
[b7d3cc34]706                        }
707                        else
708                        {
709                                /* PANIC! */
710                        }
711                }
[17a6ee9]712#if 0
713                // Disable MSN ft support for now.
[b7d3cc34]714                else if( g_strncasecmp( ct, "text/x-msmsgsinvite", 19 ) == 0 )
715                {
[9b0ad7e]716                        char *command = get_rfc822_header( body, "Invitation-Command:", blen );
717                        char *cookie = get_rfc822_header( body, "Invitation-Cookie:", blen );
[a2b99ec]718                        unsigned int icookie;
[b7d3cc34]719                       
720                        g_free( ct );
721                       
[a2b99ec]722                        /* Every invite should have both a Command and Cookie header */
723                        if( !command || !cookie ) {
724                                g_free( command );
725                                g_free( cookie );
726                                imcb_log( ic, "Warning: No command or cookie from %s", sb->who );
727                                return 1;
[b7d3cc34]728                        }
729                       
[a2b99ec]730                        icookie = strtoul( cookie, NULL, 10 );
731                        g_free( cookie );
[b7d3cc34]732                       
[a2b99ec]733                        if( g_strncasecmp( command, "INVITE", 6 ) == 0 ) {
734                                msn_invitation_invite( sb, cmd[1], icookie, body, blen );
735                        } else if( g_strncasecmp( command, "ACCEPT", 6 ) == 0 ) {
736                                msn_invitation_accept( sb, cmd[1], icookie, body, blen );
737                        } else if( g_strncasecmp( command, "CANCEL", 6 ) == 0 ) {
738                                msn_invitation_cancel( sb, cmd[1], icookie, body, blen );
739                        } else {
740                                imcb_log( ic, "Warning: Received invalid invitation with "
741                                                "command %s from %s", command, sb->who );
[b7d3cc34]742                        }
[a2b99ec]743                       
744                        g_free( command );
745                }
[17a6ee9]746#endif
[a2b99ec]747                else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 ) 
748                {
[9b1d2d6]749                        /* Not currently implemented. Don't warn about it since
750                           this seems to be used for avatars now. */
[a2b99ec]751                        g_free( ct );
[b7d3cc34]752                }
753                else if( g_strncasecmp( ct, "text/x-msmsgscontrol", 20 ) == 0 )
754                {
[9b0ad7e]755                        char *who = get_rfc822_header( msg, "TypingUser:", msglen );
[b7d3cc34]756                       
757                        if( who )
758                        {
[9624fdf]759                                imcb_buddy_typing( ic, who, OPT_TYPING );
[b7d3cc34]760                                g_free( who );
761                        }
762                       
763                        g_free( ct );
764                }
765                else
766                {
767                        g_free( ct );
768                }
769        }
770       
771        return( 1 );
772}
[9bf2481]773
[bb839e8]774static gboolean msn_sb_keepalive( gpointer data, gint source, b_input_condition cond )
[9bf2481]775{
776        struct msn_switchboard *sb = data;
777        return sb->ready && msn_sb_sendmessage( sb, SB_KEEPALIVE_MESSAGE );
778}
[bb839e8]779
780void msn_sb_start_keepalives( struct msn_switchboard *sb, gboolean initial )
781{
[f924563]782        bee_user_t *bu;
[bb839e8]783       
784        if( sb && sb->who && sb->keepalive == 0 &&
[f924563]785            ( bu = bee_user_by_handle( sb->ic->bee, sb->ic, sb->who ) ) &&
786            !( bu->flags & BEE_USER_ONLINE ) &&
[bb839e8]787            set_getbool( &sb->ic->acc->set, "switchboard_keepalives" ) )
788        {
789                if( initial )
790                        msn_sb_keepalive( sb, 0, 0 );
791               
792                sb->keepalive = b_timeout_add( 20000, msn_sb_keepalive, sb );
793        }
794}
795
796void msn_sb_stop_keepalives( struct msn_switchboard *sb )
797{
798        if( sb && sb->keepalive > 0 )
799        {
800                b_event_remove( sb->keepalive );
801                sb->keepalive = 0;
802        }
803}
Note: See TracBrowser for help on using the repository browser.