source: protocols/msn/sb.c @ 8e9e2b7

Last change on this file since 8e9e2b7 was bae0617, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-09-03T21:24:58Z

Rearrange things a bit to support multiple NS connections. This is apparently
needed for refreshing auth. tokens.

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