source: protocols/msn/sb.c @ 79bb7e4

Last change on this file since 79bb7e4 was 79bb7e4, checked in by Wilmer van der Gaast <wilmer@…>, at 2012-09-16T17:40:44Z

Online status should be read properly now.

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