source: protocols/msn/msn.c @ 24b8bbb

Last change on this file since 24b8bbb was 17a6ee9, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-04-11T14:37:06Z

Including DCC stuff again, with a wonderful extra layer of abstraction.
Some hooks are missing so sending files doesn't work yet. Receiving also
still seems to have some issues. On the plus side, at least the MSN/Jabber
modules work again.

  • Property mode set to 100644
File size: 8.7 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2004 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* MSN module - Main file; functions to be called from BitlBee          */
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 "nogaim.h"
27#include "msn.h"
28
29int msn_chat_id;
30GSList *msn_connections;
31GSList *msn_switchboards;
32
33static char *msn_set_display_name( set_t *set, char *value );
34
35static void msn_init( account_t *acc )
36{
37        set_t *s;
38       
39        s = set_add( &acc->set, "display_name", NULL, msn_set_display_name, acc );
40        s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY;
41
42        s = set_add( &acc->set, "mail_notifications", "false", set_eval_bool, acc );
43}
44
45static void msn_login( account_t *acc )
46{
47        struct im_connection *ic = imcb_new( acc );
48        struct msn_data *md = g_new0( struct msn_data, 1 );
49       
50        ic->proto_data = md;
51        md->fd = -1;
52       
53        if( strchr( acc->user, '@' ) == NULL )
54        {
55                imcb_error( ic, "Invalid account name" );
56                imc_logout( ic, FALSE );
57                return;
58        }
59       
60        imcb_log( ic, "Connecting" );
61       
62        md->fd = proxy_connect( "messenger.hotmail.com", 1863, msn_ns_connected, ic );
63        if( md->fd < 0 )
64        {
65                imcb_error( ic, "Could not connect to server" );
66                imc_logout( ic, TRUE );
67                return;
68        }
69       
70        md->ic = ic;
71        md->away_state = msn_away_state_list;
72       
73        msn_connections = g_slist_append( msn_connections, ic );
74}
75
76static void msn_logout( struct im_connection *ic )
77{
78        struct msn_data *md = ic->proto_data;
79        GSList *l;
80       
81        if( md )
82        {
83                /** Disabling MSN ft support for now.
84                while( md->filetransfers ) {
85                        imcb_file_canceled( md->filetransfers->data, "Closing connection" );
86                }
87                */
88               
89                if( md->fd >= 0 )
90                        closesocket( md->fd );
91               
92                if( md->handler )
93                {
94                        if( md->handler->rxq ) g_free( md->handler->rxq );
95                        if( md->handler->cmd_text ) g_free( md->handler->cmd_text );
96                        g_free( md->handler );
97                }
98               
99                while( md->switchboards )
100                        msn_sb_destroy( md->switchboards->data );
101               
102                msn_msgq_purge( ic, &md->msgq );
103               
104                while( md->groupcount > 0 )
105                        g_free( md->grouplist[--md->groupcount] );
106                g_free( md->grouplist );
107               
108                g_free( md );
109        }
110       
111        for( l = ic->permit; l; l = l->next )
112                g_free( l->data );
113        g_slist_free( ic->permit );
114       
115        for( l = ic->deny; l; l = l->next )
116                g_free( l->data );
117        g_slist_free( ic->deny );
118       
119        msn_connections = g_slist_remove( msn_connections, ic );
120}
121
122static int msn_buddy_msg( struct im_connection *ic, char *who, char *message, int away )
123{
124        struct msn_switchboard *sb;
125       
126        if( ( sb = msn_sb_by_handle( ic, who ) ) )
127        {
128                return( msn_sb_sendmessage( sb, message ) );
129        }
130        else
131        {
132                struct msn_message *m;
133               
134                /* Create a message. We have to arrange a usable switchboard, and send the message later. */
135                m = g_new0( struct msn_message, 1 );
136                m->who = g_strdup( who );
137                m->text = g_strdup( message );
138               
139                return msn_sb_write_msg( ic, m );
140        }
141       
142        return( 0 );
143}
144
145static GList *msn_away_states( struct im_connection *ic )
146{
147        static GList *l = NULL;
148        int i;
149       
150        if( l == NULL )
151                for( i = 0; *msn_away_state_list[i].code; i ++ )
152                        if( *msn_away_state_list[i].name )
153                                l = g_list_append( l, (void*) msn_away_state_list[i].name );
154       
155        return l;
156}
157
158static void msn_set_away( struct im_connection *ic, char *state, char *message )
159{
160        char buf[1024];
161        struct msn_data *md = ic->proto_data;
162       
163        if( state )
164                md->away_state = msn_away_state_by_name( state ) ? :
165                                 msn_away_state_list + 1;
166        else
167                md->away_state = msn_away_state_list;
168       
169        g_snprintf( buf, sizeof( buf ), "CHG %d %s\r\n", ++md->trId, md->away_state->code );
170        msn_write( ic, buf, strlen( buf ) );
171}
172
173static void msn_set_my_name( struct im_connection *ic, char *info )
174{
175        msn_set_display_name( set_find( &ic->acc->set, "display_name" ), info );
176}
177
178static void msn_get_info(struct im_connection *ic, char *who) 
179{
180        /* Just make an URL and let the user fetch the info */
181        imcb_log( ic, "%s\n%s: %s%s", _("User Info"), _("For now, fetch yourself"), PROFILE_URL, who );
182}
183
184static void msn_add_buddy( struct im_connection *ic, char *who, char *group )
185{
186        msn_buddy_list_add( ic, "FL", who, who );
187}
188
189static void msn_remove_buddy( struct im_connection *ic, char *who, char *group )
190{
191        msn_buddy_list_remove( ic, "FL", who );
192}
193
194static void msn_chat_msg( struct groupchat *c, char *message, int flags )
195{
196        struct msn_switchboard *sb = msn_sb_by_chat( c );
197       
198        if( sb )
199                msn_sb_sendmessage( sb, message );
200        /* FIXME: Error handling (although this can't happen unless something's
201           already severely broken) disappeared here! */
202}
203
204static void msn_chat_invite( struct groupchat *c, char *who, char *message )
205{
206        struct msn_switchboard *sb = msn_sb_by_chat( c );
207        char buf[1024];
208       
209        if( sb )
210        {
211                g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, who );
212                msn_sb_write( sb, buf, strlen( buf ) );
213        }
214}
215
216static void msn_chat_leave( struct groupchat *c )
217{
218        struct msn_switchboard *sb = msn_sb_by_chat( c );
219       
220        if( sb )
221                msn_sb_write( sb, "OUT\r\n", 5 );
222}
223
224static struct groupchat *msn_chat_with( struct im_connection *ic, char *who )
225{
226        struct msn_switchboard *sb;
227       
228        if( ( sb = msn_sb_by_handle( ic, who ) ) )
229        {
230                debug( "Converting existing switchboard to %s to a groupchat", who );
231                return msn_sb_to_chat( sb );
232        }
233        else
234        {
235                struct msn_message *m;
236               
237                /* Create a magic message. This is quite hackish, but who cares? :-P */
238                m = g_new0( struct msn_message, 1 );
239                m->who = g_strdup( who );
240                m->text = g_strdup( GROUPCHAT_SWITCHBOARD_MESSAGE );
241               
242                msn_sb_write_msg( ic, m );
243
244                return NULL;
245        }
246       
247        return NULL;
248}
249
250static void msn_keepalive( struct im_connection *ic )
251{
252        msn_write( ic, "PNG\r\n", strlen( "PNG\r\n" ) );
253}
254
255static void msn_add_permit( struct im_connection *ic, char *who )
256{
257        msn_buddy_list_add( ic, "AL", who, who );
258}
259
260static void msn_rem_permit( struct im_connection *ic, char *who )
261{
262        msn_buddy_list_remove( ic, "AL", who );
263}
264
265static void msn_add_deny( struct im_connection *ic, char *who )
266{
267        struct msn_switchboard *sb;
268       
269        msn_buddy_list_add( ic, "BL", who, who );
270       
271        /* If there's still a conversation with this person, close it. */
272        if( ( sb = msn_sb_by_handle( ic, who ) ) )
273        {
274                msn_sb_destroy( sb );
275        }
276}
277
278static void msn_rem_deny( struct im_connection *ic, char *who )
279{
280        msn_buddy_list_remove( ic, "BL", who );
281}
282
283static int msn_send_typing( struct im_connection *ic, char *who, int typing )
284{
285        if( typing & OPT_TYPING )
286                return( msn_buddy_msg( ic, who, TYPING_NOTIFICATION_MESSAGE, 0 ) );
287        else
288                return( 1 );
289}
290
291static char *msn_set_display_name( set_t *set, char *value )
292{
293        account_t *acc = set->data;
294        struct im_connection *ic = acc->ic;
295        struct msn_data *md;
296        char buf[1024], *fn;
297       
298        /* Double-check. */
299        if( ic == NULL )
300                return NULL;
301       
302        md = ic->proto_data;
303       
304        if( strlen( value ) > 129 )
305        {
306                imcb_log( ic, "Maximum name length exceeded" );
307                return NULL;
308        }
309       
310        fn = msn_http_encode( value );
311       
312        g_snprintf( buf, sizeof( buf ), "REA %d %s %s\r\n", ++md->trId, ic->acc->user, fn );
313        msn_write( ic, buf, strlen( buf ) );
314        g_free( fn );
315       
316        /* Returning NULL would be better, because the server still has to
317           confirm the name change. However, it looks a bit confusing to the
318           user. */
319        return value;
320}
321
322void msn_initmodule()
323{
324        struct prpl *ret = g_new0(struct prpl, 1);
325       
326        ret->name = "msn";
327        ret->login = msn_login;
328        ret->init = msn_init;
329        ret->logout = msn_logout;
330        ret->buddy_msg = msn_buddy_msg;
331        ret->away_states = msn_away_states;
332        ret->set_away = msn_set_away;
333        ret->get_info = msn_get_info;
334        ret->set_my_name = msn_set_my_name;
335        ret->add_buddy = msn_add_buddy;
336        ret->remove_buddy = msn_remove_buddy;
337        ret->chat_msg = msn_chat_msg;
338        ret->chat_invite = msn_chat_invite;
339        ret->chat_leave = msn_chat_leave;
340        ret->chat_with = msn_chat_with;
341        ret->keepalive = msn_keepalive;
342        ret->add_permit = msn_add_permit;
343        ret->rem_permit = msn_rem_permit;
344        ret->add_deny = msn_add_deny;
345        ret->rem_deny = msn_rem_deny;
346        ret->send_typing = msn_send_typing;
347        ret->handle_cmp = g_strcasecmp;
348        //ret->transfer_request = msn_ftp_transfer_request;
349
350        register_protocol(ret);
351}
Note: See TracBrowser for help on using the repository browser.