Changeset 8e9e2b7 for protocols/msn
- Timestamp:
- 2010-10-03T02:45:26Z (14 years ago)
- Branches:
- master
- Children:
- 04f0c10
- Parents:
- 88de0c9 (diff), 2af3e23 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Location:
- protocols/msn
- Files:
-
- 2 added
- 2 deleted
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/msn/Makefile
r88de0c9 r8e9e2b7 13 13 14 14 # [SH] Program variables 15 objects = msn.o msn_util.o ns.o passport.o sb.o tables.o15 objects = msn.o msn_util.o ns.o sb.o soap.o tables.o 16 16 17 17 LFLAGS += -r -
protocols/msn/msn.c
r88de0c9 r8e9e2b7 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-20 04Wilmer van der Gaast and others *4 * Copyright 2002-2010 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 25 25 26 26 #include "nogaim.h" 27 #include "soap.h" 27 28 #include "msn.h" 28 29 … … 35 36 static void msn_init( account_t *acc ) 36 37 { 37 set_add( &acc->set, "display_name", NULL, set_eval_display_name, acc ); 38 set_add( &acc->set, "local_display_name", "false", set_eval_bool, acc ); 38 set_t *s; 39 40 s = set_add( &acc->set, "display_name", NULL, set_eval_display_name, acc ); 41 s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY; 42 39 43 set_add( &acc->set, "mail_notifications", "false", set_eval_bool, acc ); 40 44 set_add( &acc->set, "switchboard_keepalives", "false", set_eval_bool, acc ); 45 46 acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE; 41 47 } 42 48 … … 47 53 48 54 ic->proto_data = md; 49 md->fd = -1;50 55 51 56 if( strchr( acc->user, '@' ) == NULL ) … … 56 61 } 57 62 58 imcb_log( ic, "Connecting" );59 60 md->fd = proxy_connect( "messenger.hotmail.com", 1863, msn_ns_connected, ic );61 if( md->fd < 0 )62 {63 imcb_error( ic, "Could not connect to server" );64 imc_logout( ic, TRUE );65 return;66 }67 68 63 md->ic = ic; 69 64 md->away_state = msn_away_state_list; 70 71 msn_connections = g_slist_append( msn_connections, ic ); 65 md->domaintree = g_tree_new( msn_domaintree_cmp ); 66 md->ns->fd = -1; 67 68 msn_connections = g_slist_prepend( msn_connections, ic ); 69 70 imcb_log( ic, "Connecting" ); 71 msn_ns_connect( ic, md->ns, MSN_NS_HOST, MSN_NS_PORT ); 72 72 } 73 73 … … 76 76 struct msn_data *md = ic->proto_data; 77 77 GSList *l; 78 int i; 78 79 79 80 if( md ) … … 85 86 */ 86 87 87 if( md->fd >= 0 ) 88 closesocket( md->fd ); 89 90 if( md->handler ) 91 { 92 if( md->handler->rxq ) g_free( md->handler->rxq ); 93 if( md->handler->cmd_text ) g_free( md->handler->cmd_text ); 94 g_free( md->handler ); 95 } 88 msn_ns_close( md->ns ); 96 89 97 90 while( md->switchboards ) … … 99 92 100 93 msn_msgq_purge( ic, &md->msgq ); 101 102 while( md->groupcount > 0 ) 103 g_free( md->grouplist[--md->groupcount] ); 104 g_free( md->grouplist ); 94 msn_soapq_flush( ic, FALSE ); 95 96 for( i = 0; i < sizeof( md->tokens ) / sizeof( md->tokens[0] ); i ++ ) 97 g_free( md->tokens[i] ); 98 g_free( md->lock_key ); 99 g_free( md->pp_policy ); 100 101 while( md->groups ) 102 { 103 struct msn_group *mg = md->groups->data; 104 g_free( mg->id ); 105 g_free( mg->name ); 106 g_free( mg ); 107 md->groups = g_slist_remove( md->groups, mg ); 108 } 109 110 g_tree_destroy( md->domaintree ); 111 md->domaintree = NULL; 105 112 106 113 while( md->grpq ) … … 134 141 if( strcmp( who, "raw" ) == 0 ) 135 142 { 136 msn_write( ic, message, strlen( message ) ); 137 msn_write( ic, "\r\n", 2 ); 143 msn_ns_write( ic, -1, "%s\r\n", message ); 138 144 } 139 145 else … … 173 179 static void msn_set_away( struct im_connection *ic, char *state, char *message ) 174 180 { 175 char buf[1024];181 char *uux; 176 182 struct msn_data *md = ic->proto_data; 177 183 … … 181 187 md->away_state = msn_away_state_list + 1; 182 188 183 g_snprintf( buf, sizeof( buf ), "CHG %d %s\r\n", ++md->trId, md->away_state->code );184 msn_write( ic, buf, strlen( buf ) );185 } 186 187 static void msn_set_my_name( struct im_connection *ic, char *info ) 188 { 189 msn_set_display_name( ic, info);189 if( !msn_ns_write( ic, -1, "CHG %d %s\r\n", ++md->trId, md->away_state->code ) ) 190 return; 191 192 uux = g_markup_printf_escaped( "<Data><PSM>%s</PSM><CurrentMedia></CurrentMedia>" 193 "</Data>", message ? message : "" ); 194 msn_ns_write( ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen( uux ), uux ); 195 g_free( uux ); 190 196 } 191 197 … … 200 206 struct bee_user *bu = bee_user_by_handle( ic->bee, ic, who ); 201 207 202 msn_buddy_list_add( ic, "FL", who, who, group );208 msn_buddy_list_add( ic, MSN_BUDDY_FL, who, who, group ); 203 209 if( bu && bu->group ) 204 msn_buddy_list_remove( ic, "FL", who, bu->group->name );210 msn_buddy_list_remove( ic, MSN_BUDDY_FL, who, bu->group->name ); 205 211 } 206 212 207 213 static void msn_remove_buddy( struct im_connection *ic, char *who, char *group ) 208 214 { 209 msn_buddy_list_remove( ic, "FL", who, NULL );215 msn_buddy_list_remove( ic, MSN_BUDDY_FL, who, NULL ); 210 216 } 211 217 … … 267 273 static void msn_keepalive( struct im_connection *ic ) 268 274 { 269 msn_ write( ic, "PNG\r\n", strlen( "PNG\r\n" ));275 msn_ns_write( ic, -1, "PNG\r\n" ); 270 276 } 271 277 272 278 static void msn_add_permit( struct im_connection *ic, char *who ) 273 279 { 274 msn_buddy_list_add( ic, "AL", who, who, NULL );280 msn_buddy_list_add( ic, MSN_BUDDY_AL, who, who, NULL ); 275 281 } 276 282 277 283 static void msn_rem_permit( struct im_connection *ic, char *who ) 278 284 { 279 msn_buddy_list_remove( ic, "AL", who, NULL );285 msn_buddy_list_remove( ic, MSN_BUDDY_AL, who, NULL ); 280 286 } 281 287 … … 284 290 struct msn_switchboard *sb; 285 291 286 msn_buddy_list_add( ic, "BL", who, who, NULL );292 msn_buddy_list_add( ic, MSN_BUDDY_BL, who, who, NULL ); 287 293 288 294 /* If there's still a conversation with this person, close it. */ … … 295 301 static void msn_rem_deny( struct im_connection *ic, char *who ) 296 302 { 297 msn_buddy_list_remove( ic, "BL", who, NULL );303 msn_buddy_list_remove( ic, MSN_BUDDY_BL, who, NULL ); 298 304 } 299 305 … … 314 320 account_t *acc = set->data; 315 321 struct im_connection *ic = acc->ic; 316 317 /* Allow any name if we're offline. */ 318 if( ic == NULL ) 319 return value; 322 struct msn_data *md = ic->proto_data; 320 323 321 324 if( strlen( value ) > 129 ) … … 325 328 } 326 329 327 /* Returning NULL would be better, because the server still has to 328 confirm the name change. However, it looks a bit confusing to the 329 user. */ 330 return msn_set_display_name( ic, value ) ? value : NULL; 330 if( md->flags & MSN_GOT_PROFILE_DN ) 331 imcb_log( ic, "Warning: Persistent name changes for this account have to be done " 332 "in the profile. BitlBee doesn't currently support this." ); 333 334 msn_soap_addressbook_set_display_name( ic, value ); 335 return msn_ns_set_display_name( ic, value ) ? value : NULL; 336 } 337 338 static void msn_buddy_data_add( bee_user_t *bu ) 339 { 340 struct msn_data *md = bu->ic->proto_data; 341 bu->data = g_new0( struct msn_buddy_data, 1 ); 342 g_tree_insert( md->domaintree, bu->handle, bu ); 343 } 344 345 static void msn_buddy_data_free( bee_user_t *bu ) 346 { 347 struct msn_data *md = bu->ic->proto_data; 348 g_tree_remove( md->domaintree, bu->handle ); 349 g_free( bu->data ); 331 350 } 332 351 … … 344 363 ret->set_away = msn_set_away; 345 364 ret->get_info = msn_get_info; 346 ret->set_my_name = msn_set_my_name;347 365 ret->add_buddy = msn_add_buddy; 348 366 ret->remove_buddy = msn_remove_buddy; … … 358 376 ret->send_typing = msn_send_typing; 359 377 ret->handle_cmp = g_strcasecmp; 378 ret->buddy_data_add = msn_buddy_data_add; 379 ret->buddy_data_free = msn_buddy_data_free; 380 360 381 //ret->transfer_request = msn_ftp_transfer_request; 361 382 -
protocols/msn/msn.h
r88de0c9 r8e9e2b7 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-20 04Wilmer van der Gaast and others *4 * Copyright 2002-2010 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 39 39 #endif 40 40 41 #define QRY_NAME "msmsgs@msnmsgr.com" 42 #define QRY_CODE "Q1P7W2E4J9R8U3S5" 41 /* This should be MSN Messenger 7.0.0813 42 #define MSNP11_PROD_KEY "CFHUR$52U_{VIX5T" 43 #define MSNP11_PROD_ID "PROD0101{0RM?UBW" 44 */ 45 46 #define MSN_NS_HOST "messenger.hotmail.com" 47 #define MSN_NS_PORT 1863 48 49 /* Some other version. 50 #define MSNP11_PROD_KEY "O4BG@C7BWLYQX?5G" 51 #define MSNP11_PROD_ID "PROD01065C%ZFN6F" 52 */ 53 54 #define MSNP11_PROD_KEY "ILTXC!4IXB5FB*PX" 55 #define MSNP11_PROD_ID "PROD0119GSJUC$18" 56 #define MSNP_VER "MSNP15" 57 #define MSNP_BUILD "8.5.1288" 43 58 44 59 #define MSN_SB_NEW -24062002 … … 61 76 #define PROFILE_URL "http://members.msn.com/" 62 77 78 typedef enum 79 { 80 MSN_GOT_PROFILE = 1, 81 MSN_GOT_PROFILE_DN = 2, 82 MSN_DONE_ADL = 4, 83 MSN_REAUTHING = 8, 84 } msn_flags_t; 85 86 struct msn_handler_data 87 { 88 int fd, inpa; 89 int rxlen; 90 char *rxq; 91 92 int msglen; 93 char *cmd_text; 94 95 /* Either ic or sb */ 96 gpointer data; 97 98 int (*exec_command) ( struct msn_handler_data *handler, char **cmd, int count ); 99 int (*exec_message) ( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int count ); 100 }; 101 63 102 struct msn_data 64 103 { 65 104 struct im_connection *ic; 66 105 67 int fd;68 struct msn_handler_data *handler;106 struct msn_handler_data ns[1]; 107 msn_flags_t flags; 69 108 70 109 int trId; 71 72 GSList *msgq, *grpq; 110 char *tokens[4]; 111 char *lock_key, *pp_policy; 112 113 GSList *msgq, *grpq, *soapq; 73 114 GSList *switchboards; 74 115 int sb_failures; 75 116 time_t first_sb_failure; 76 GSList *filetransfers;77 117 78 118 const struct msn_away_state *away_state; 79 int buddycount; 80 int groupcount; 81 char **grouplist; 119 GSList *groups; 120 121 /* Mostly used for sending the ADL command; since MSNP13 the client 122 is responsible for downloading the contact list and then sending 123 it to the MSNP server. */ 124 GTree *domaintree; 125 int adl_todo; 82 126 }; 83 127 … … 86 130 struct im_connection *ic; 87 131 132 /* The following two are also in the handler. TODO: Clean up. */ 88 133 int fd; 89 134 gint inp; … … 127 172 }; 128 173 129 struct msn_handler_data 130 { 131 int fd; 132 int rxlen; 133 char *rxq; 134 135 int msglen; 136 char *cmd_text; 137 138 gpointer data; 139 140 int (*exec_command) ( gpointer data, char **cmd, int count ); 141 int (*exec_message) ( gpointer data, char *msg, int msglen, char **cmd, int count ); 174 typedef enum 175 { 176 MSN_BUDDY_FL = 1, /* Warning: FL,AL,BL *must* be 1,2,4. */ 177 MSN_BUDDY_AL = 2, 178 MSN_BUDDY_BL = 4, 179 MSN_BUDDY_RL = 8, 180 MSN_BUDDY_PL = 16, 181 MSN_BUDDY_ADL_SYNCED = 256, 182 } msn_buddy_flags_t; 183 184 struct msn_buddy_data 185 { 186 char *cid; 187 msn_buddy_flags_t flags; 188 }; 189 190 struct msn_group 191 { 192 char *name; 193 char *id; 142 194 }; 143 195 … … 161 213 162 214 /* ns.c */ 163 gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ); 215 int msn_ns_write( struct im_connection *ic, int fd, const char *fmt, ... ); 216 gboolean msn_ns_connect( struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port ); 217 void msn_ns_close( struct msn_handler_data *handler ); 218 void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error ); 219 void msn_auth_got_contact_list( struct im_connection *ic ); 220 int msn_ns_finish_login( struct im_connection *ic ); 164 221 165 222 /* msn_util.c */ 166 int msn_write( struct im_connection *ic, char *s, int len );167 223 int msn_logged_in( struct im_connection *ic ); 168 int msn_buddy_list_add( struct im_connection *ic, const char *list, const char *who, const char *realname_, const char *group );169 int msn_buddy_list_remove( struct im_connection *ic, char *list, const char *who, const char *group );170 void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname);224 int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname_, const char *group ); 225 int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group ); 226 void msn_buddy_ask( bee_user_t *bu ); 171 227 char *msn_findheader( char *text, char *header, int len ); 172 228 char **msn_linesplit( char *line ); 173 229 int msn_handler( struct msn_handler_data *h ); 174 char *msn_http_encode( const char *input );175 230 void msn_msgq_purge( struct im_connection *ic, GSList **list ); 176 gboolean msn_set_display_name( struct im_connection *ic, const char *rawname ); 231 char *msn_p11_challenge( char *challenge ); 232 gint msn_domaintree_cmp( gconstpointer a_, gconstpointer b_ ); 233 struct msn_group *msn_group_by_name( struct im_connection *ic, const char *name ); 234 struct msn_group *msn_group_by_id( struct im_connection *ic, const char *id ); 235 int msn_ns_set_display_name( struct im_connection *ic, const char *value ); 177 236 178 237 /* tables.c */ … … 183 242 184 243 /* sb.c */ 185 int msn_sb_write( struct msn_switchboard *sb, c har *s, int len);244 int msn_sb_write( struct msn_switchboard *sb, const char *fmt, ... ); 186 245 struct msn_switchboard *msn_sb_create( struct im_connection *ic, char *host, int port, char *key, int session ); 187 246 struct msn_switchboard *msn_sb_by_handle( struct im_connection *ic, char *handle ); … … 196 255 void msn_sb_stop_keepalives( struct msn_switchboard *sb ); 197 256 198 /* invitation.c */199 void msn_ftp_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who );200 201 257 #endif //_MSN_H -
protocols/msn/msn_util.c
r88de0c9 r8e9e2b7 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-20 04Wilmer van der Gaast and others *4 * Copyright 2002-2010 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 26 26 #include "nogaim.h" 27 27 #include "msn.h" 28 #include "md5.h" 29 #include "soap.h" 28 30 #include <ctype.h> 29 31 30 int msn_write( struct im_connection *ic, char *s, int len ) 32 int msn_logged_in( struct im_connection *ic ) 33 { 34 imcb_connected( ic ); 35 36 return( 0 ); 37 } 38 39 static char *adlrml_entry( const char *handle_, msn_buddy_flags_t list ) 40 { 41 char *domain, handle[strlen(handle_)+1]; 42 43 strcpy( handle, handle_ ); 44 if( ( domain = strchr( handle, '@' ) ) ) 45 *(domain++) = '\0'; 46 else 47 return NULL; 48 49 return g_markup_printf_escaped( "<ml><d n=\"%s\"><c n=\"%s\" l=\"%d\" t=\"1\"/></d></ml>", 50 domain, handle, list ); 51 } 52 53 int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname, const char *group ) 31 54 { 32 55 struct msn_data *md = ic->proto_data; 33 int st; 34 35 st = write( md->fd, s, len ); 36 if( st != len ) 37 { 38 imcb_error( ic, "Short write() to main server" ); 39 imc_logout( ic, TRUE ); 40 return 0; 41 } 42 43 return 1; 44 } 45 46 int msn_logged_in( struct im_connection *ic ) 47 { 48 imcb_connected( ic ); 49 50 return( 0 ); 51 } 52 53 int msn_buddy_list_add( struct im_connection *ic, const char *list, const char *who, const char *realname_, const char *group ) 54 { 55 struct msn_data *md = ic->proto_data; 56 char buf[1024], *realname, groupid[8]; 56 char groupid[8]; 57 bee_user_t *bu; 58 struct msn_buddy_data *bd; 59 char *adl; 57 60 58 61 *groupid = '\0'; 62 #if 0 59 63 if( group ) 60 64 { … … 87 91 if( l == NULL ) 88 92 { 89 char *groupname = msn_http_encode( group ); 93 char groupname[strlen(group)+1]; 94 strcpy( groupname, group ); 95 http_encode( groupname ); 90 96 g_snprintf( buf, sizeof( buf ), "ADG %d %s %d\r\n", ++md->trId, groupname, 0 ); 91 g_free( groupname );92 97 return msn_write( ic, buf, strlen( buf ) ); 93 98 } … … 101 106 } 102 107 } 103 104 realname = msn_http_encode( realname_ ); 105 g_snprintf( buf, sizeof( buf ), "ADD %d %s %s %s%s\r\n", ++md->trId, list, who, realname, groupid ); 106 g_free( realname ); 107 108 return msn_write( ic, buf, strlen( buf ) ); 109 } 110 111 int msn_buddy_list_remove( struct im_connection *ic, char *list, const char *who, const char *group ) 108 #endif 109 110 if( !( ( bu = bee_user_by_handle( ic->bee, ic, who ) ) || 111 ( bu = bee_user_new( ic->bee, ic, who, 0 ) ) ) || 112 !( bd = bu->data ) || bd->flags & list ) 113 return 1; 114 115 bd->flags |= list; 116 117 if( list == MSN_BUDDY_FL ) 118 msn_soap_ab_contact_add( ic, bu ); 119 else 120 msn_soap_memlist_edit( ic, who, TRUE, list ); 121 122 if( ( adl = adlrml_entry( who, list ) ) ) 123 { 124 int st = msn_ns_write( ic, -1, "ADL %d %zd\r\n%s", 125 ++md->trId, strlen( adl ), adl ); 126 g_free( adl ); 127 128 return st; 129 } 130 131 return 1; 132 } 133 134 int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group ) 112 135 { 113 136 struct msn_data *md = ic->proto_data; 114 char buf[1024], groupid[8]; 137 char groupid[8]; 138 bee_user_t *bu; 139 struct msn_buddy_data *bd; 140 char *adl; 115 141 116 142 *groupid = '\0'; 143 #if 0 117 144 if( group ) 118 145 { … … 125 152 } 126 153 } 127 128 g_snprintf( buf, sizeof( buf ), "REM %d %s %s%s\r\n", ++md->trId, list, who, groupid ); 129 if( msn_write( ic, buf, strlen( buf ) ) ) 130 return( 1 ); 131 132 return( 0 ); 154 #endif 155 156 if( !( bu = bee_user_by_handle( ic->bee, ic, who ) ) || 157 !( bd = bu->data ) || !( bd->flags & list ) ) 158 return 1; 159 160 bd->flags &= ~list; 161 162 if( list == MSN_BUDDY_FL ) 163 msn_soap_ab_contact_del( ic, bu ); 164 else 165 msn_soap_memlist_edit( ic, who, FALSE, list ); 166 167 if( ( adl = adlrml_entry( who, list ) ) ) 168 { 169 int st = msn_ns_write( ic, -1, "RML %d %zd\r\n%s", 170 ++md->trId, strlen( adl ), adl ); 171 g_free( adl ); 172 173 return st; 174 } 175 176 return 1; 133 177 } 134 178 … … 144 188 struct msn_buddy_ask_data *bla = data; 145 189 146 msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname, NULL );190 msn_buddy_list_add( bla->ic, MSN_BUDDY_AL, bla->handle, bla->realname, NULL ); 147 191 148 192 imcb_ask_add( bla->ic, bla->handle, NULL ); … … 157 201 struct msn_buddy_ask_data *bla = data; 158 202 159 msn_buddy_list_add( bla->ic, "BL", bla->handle, bla->realname, NULL );203 msn_buddy_list_add( bla->ic, MSN_BUDDY_BL, bla->handle, bla->realname, NULL ); 160 204 161 205 g_free( bla->handle ); … … 164 208 } 165 209 166 void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname ) 167 { 168 struct msn_buddy_ask_data *bla = g_new0( struct msn_buddy_ask_data, 1 ); 210 void msn_buddy_ask( bee_user_t *bu ) 211 { 212 struct msn_buddy_ask_data *bla; 213 struct msn_buddy_data *bd = bu->data; 169 214 char buf[1024]; 170 215 171 bla->ic = ic; 172 bla->handle = g_strdup( handle ); 173 bla->realname = g_strdup( realname ); 216 if( ( bd->flags & 30 ) != 8 && ( bd->flags & 30 ) != 16 ) 217 return; 218 219 bla = g_new0( struct msn_buddy_ask_data, 1 ); 220 bla->ic = bu->ic; 221 bla->handle = g_strdup( bu->handle ); 222 bla->realname = g_strdup( bu->fullname ); 174 223 175 224 g_snprintf( buf, sizeof( buf ), 176 225 "The user %s (%s) wants to add you to his/her buddy list.", 177 handle, realname );178 imcb_ask( ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no );226 bu->handle, bu->fullname ); 227 imcb_ask( bu->ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no ); 179 228 } 180 229 … … 279 328 if( st <= 0 ) 280 329 return( -1 ); 330 331 if( getenv( "BITLBEE_DEBUG" ) ) 332 { 333 write( 2, "->C:", 4 ); 334 write( 2, h->rxq + h->rxlen - st, st ); 335 } 281 336 282 337 while( st ) … … 296 351 cmd = msn_linesplit( cmd_text ); 297 352 for( count = 0; cmd[count]; count ++ ); 298 st = h->exec_command( h ->data, cmd, count );353 st = h->exec_command( h, cmd, count ); 299 354 g_free( cmd_text ); 300 355 … … 331 386 for( count = 0; cmd[count]; count ++ ); 332 387 333 st = h->exec_message( h ->data, msg, h->msglen, cmd, count );388 st = h->exec_message( h, msg, h->msglen, cmd, count ); 334 389 g_free( msg ); 335 390 g_free( h->cmd_text ); … … 367 422 } 368 423 369 /* The difference between this function and the normal http_encode() function370 is that this one escapes every 7-bit ASCII character because this is said371 to avoid some lame server-side checks when setting a real-name. Also,372 non-ASCII characters are not escaped because MSN servers don't seem to373 appreciate that! */374 char *msn_http_encode( const char *input )375 {376 char *ret, *s;377 int i;378 379 ret = s = g_new0( char, strlen( input ) * 3 + 1 );380 for( i = 0; input[i]; i ++ )381 if( input[i] & 128 )382 {383 *s = input[i];384 s ++;385 }386 else387 {388 g_snprintf( s, 4, "%%%02X", input[i] );389 s += 3;390 }391 392 return ret;393 }394 395 424 void msn_msgq_purge( struct im_connection *ic, GSList **list ) 396 425 { … … 433 462 } 434 463 435 gboolean msn_set_display_name( struct im_connection *ic, const char *rawname ) 436 { 437 char *fn = msn_http_encode( rawname ); 464 /* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */ 465 char *msn_p11_challenge( char *challenge ) 466 { 467 char *output, buf[256]; 468 md5_state_t md5c; 469 unsigned char md5Hash[16], *newHash; 470 unsigned int *md5Parts, *chlStringParts, newHashParts[5]; 471 long long nHigh = 0, nLow = 0; 472 int i, n; 473 474 /* Create the MD5 hash */ 475 md5_init(&md5c); 476 md5_append(&md5c, (unsigned char*) challenge, strlen(challenge)); 477 md5_append(&md5c, (unsigned char*) MSNP11_PROD_KEY, strlen(MSNP11_PROD_KEY)); 478 md5_finish(&md5c, md5Hash); 479 480 /* Split it into four integers */ 481 md5Parts = (unsigned int *)md5Hash; 482 for (i = 0; i < 4; i ++) 483 { 484 md5Parts[i] = GUINT32_TO_LE(md5Parts[i]); 485 486 /* & each integer with 0x7FFFFFFF */ 487 /* and save one unmodified array for later */ 488 newHashParts[i] = md5Parts[i]; 489 md5Parts[i] &= 0x7FFFFFFF; 490 } 491 492 /* make a new string and pad with '0' */ 493 n = g_snprintf(buf, sizeof(buf)-5, "%s%s00000000", challenge, MSNP11_PROD_ID); 494 /* truncate at an 8-byte boundary */ 495 buf[n&=~7] = '\0'; 496 497 /* split into integers */ 498 chlStringParts = (unsigned int *)buf; 499 500 /* this is magic */ 501 for (i = 0; i < (n / 4) - 1; i += 2) 502 { 503 long long temp; 504 505 chlStringParts[i] = GUINT32_TO_LE(chlStringParts[i]); 506 chlStringParts[i+1] = GUINT32_TO_LE(chlStringParts[i+1]); 507 508 temp = (md5Parts[0] * (((0x0E79A9C1 * (long long)chlStringParts[i]) % 0x7FFFFFFF)+nHigh) + md5Parts[1])%0x7FFFFFFF; 509 nHigh = (md5Parts[2] * (((long long)chlStringParts[i+1]+temp) % 0x7FFFFFFF) + md5Parts[3]) % 0x7FFFFFFF; 510 nLow = nLow + nHigh + temp; 511 } 512 nHigh = (nHigh+md5Parts[1]) % 0x7FFFFFFF; 513 nLow = (nLow+md5Parts[3]) % 0x7FFFFFFF; 514 515 newHashParts[0] ^= nHigh; 516 newHashParts[1] ^= nLow; 517 newHashParts[2] ^= nHigh; 518 newHashParts[3] ^= nLow; 519 520 /* swap more bytes if big endian */ 521 for (i = 0; i < 4; i ++) 522 newHashParts[i] = GUINT32_TO_LE(newHashParts[i]); 523 524 /* make a string of the parts */ 525 newHash = (unsigned char *)newHashParts; 526 527 /* convert to hexadecimal */ 528 output = g_new(char, 33); 529 for (i = 0; i < 16; i ++) 530 sprintf(output + i * 2, "%02x", newHash[i]); 531 532 return output; 533 } 534 535 gint msn_domaintree_cmp( gconstpointer a_, gconstpointer b_ ) 536 { 537 const char *a = a_, *b = b_; 538 gint ret; 539 540 if( !( a = strchr( a, '@' ) ) || !( b = strchr( b, '@' ) ) || 541 ( ret = strcmp( a, b ) ) == 0 ) 542 ret = strcmp( a_, b_ ); 543 544 return ret; 545 } 546 547 struct msn_group *msn_group_by_name( struct im_connection *ic, const char *name ) 548 { 438 549 struct msn_data *md = ic->proto_data; 439 char buf[1024]; 440 441 g_snprintf( buf, sizeof( buf ), "REA %d %s %s\r\n", ++md->trId, ic->acc->user, fn ); 442 g_free( fn ); 443 444 return msn_write( ic, buf, strlen( buf ) ) != 0; 445 } 550 GSList *l; 551 552 for( l = md->groups; l; l = l->next ) 553 { 554 struct msn_group *mg = l->data; 555 556 if( g_strcasecmp( mg->name, name ) == 0 ) 557 return mg; 558 } 559 560 return NULL; 561 } 562 563 struct msn_group *msn_group_by_id( struct im_connection *ic, const char *id ) 564 { 565 struct msn_data *md = ic->proto_data; 566 GSList *l; 567 568 for( l = md->groups; l; l = l->next ) 569 { 570 struct msn_group *mg = l->data; 571 572 if( g_strcasecmp( mg->id, id ) == 0 ) 573 return mg; 574 } 575 576 return NULL; 577 } 578 579 int msn_ns_set_display_name( struct im_connection *ic, const char *value ) 580 { 581 struct msn_data *md = ic->proto_data; 582 char fn[strlen(value)*3+1]; 583 584 strcpy( fn, value ); 585 http_encode( fn ); 586 587 /* Note: We don't actually know if the server accepted the new name, 588 and won't give proper feedback yet if it doesn't. */ 589 return msn_ns_write( ic, -1, "PRP %d MFN %s\r\n", ++md->trId, fn ); 590 } -
protocols/msn/ns.c
r88de0c9 r8e9e2b7 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-20 04Wilmer van der Gaast and others *4 * Copyright 2002-2010 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 27 27 #include "nogaim.h" 28 28 #include "msn.h" 29 #include "passport.h"30 29 #include "md5.h" 31 30 #include "soap.h" 31 #include "xmltree.h" 32 33 static gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ); 32 34 static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond ); 33 static int msn_ns_command( gpointer data, char **cmd, int num_parts ); 34 static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); 35 36 static void msn_auth_got_passport_token( struct msn_auth_data *mad ); 37 static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name ); 38 39 gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) 40 { 41 struct im_connection *ic = data; 42 struct msn_data *md; 43 char s[1024]; 44 45 if( !g_slist_find( msn_connections, ic ) ) 46 return FALSE; 47 48 if( source == -1 ) 35 static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num_parts ); 36 static int msn_ns_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts ); 37 38 static void msn_ns_send_adl_start( struct im_connection *ic ); 39 static void msn_ns_send_adl( struct im_connection *ic ); 40 41 int msn_ns_write( struct im_connection *ic, int fd, const char *fmt, ... ) 42 { 43 struct msn_data *md = ic->proto_data; 44 va_list params; 45 char *out; 46 size_t len; 47 int st; 48 49 va_start( params, fmt ); 50 out = g_strdup_vprintf( fmt, params ); 51 va_end( params ); 52 53 if( fd < 0 ) 54 fd = md->ns->fd; 55 56 if( getenv( "BITLBEE_DEBUG" ) ) 57 fprintf( stderr, "->NS%d:%s", fd, out ); 58 59 len = strlen( out ); 60 st = write( fd, out, len ); 61 g_free( out ); 62 if( st != len ) 63 { 64 imcb_error( ic, "Short write() to main server" ); 65 imc_logout( ic, TRUE ); 66 return 0; 67 } 68 69 return 1; 70 } 71 72 gboolean msn_ns_connect( struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port ) 73 { 74 if( handler->fd >= 0 ) 75 closesocket( handler->fd ); 76 77 handler->exec_command = msn_ns_command; 78 handler->exec_message = msn_ns_message; 79 handler->data = ic; 80 handler->fd = proxy_connect( host, port, msn_ns_connected, handler ); 81 if( handler->fd < 0 ) 49 82 { 50 83 imcb_error( ic, "Could not connect to server" ); … … 53 86 } 54 87 88 return TRUE; 89 } 90 91 static gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) 92 { 93 struct msn_handler_data *handler = data; 94 struct im_connection *ic = handler->data; 95 struct msn_data *md; 96 97 if( !g_slist_find( msn_connections, ic ) ) 98 return FALSE; 99 55 100 md = ic->proto_data; 56 101 57 if( !md->handler ) 58 { 59 md->handler = g_new0( struct msn_handler_data, 1 ); 60 md->handler->data = ic; 61 md->handler->exec_command = msn_ns_command; 62 md->handler->exec_message = msn_ns_message; 63 } 64 else 65 { 66 if( md->handler->rxq ) 67 g_free( md->handler->rxq ); 68 69 md->handler->rxlen = 0; 70 } 71 72 md->handler->fd = md->fd; 73 md->handler->rxq = g_new0( char, 1 ); 74 75 g_snprintf( s, sizeof( s ), "VER %d MSNP8 CVR0\r\n", ++md->trId ); 76 if( msn_write( ic, s, strlen( s ) ) ) 77 { 78 ic->inpa = b_input_add( md->fd, B_EV_IO_READ, msn_ns_callback, ic ); 102 if( source == -1 ) 103 { 104 imcb_error( ic, "Could not connect to server" ); 105 imc_logout( ic, TRUE ); 106 return FALSE; 107 } 108 109 g_free( handler->rxq ); 110 handler->rxlen = 0; 111 handler->rxq = g_new0( char, 1 ); 112 113 if( msn_ns_write( ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER ) ) 114 { 115 handler->inpa = b_input_add( handler->fd, B_EV_IO_READ, msn_ns_callback, handler ); 79 116 imcb_log( ic, "Connected to server, waiting for reply" ); 80 117 } … … 83 120 } 84 121 122 void msn_ns_close( struct msn_handler_data *handler ) 123 { 124 if( handler->fd >= 0 ) 125 { 126 closesocket( handler->fd ); 127 b_event_remove( handler->inpa ); 128 } 129 130 handler->fd = handler->inpa = -1; 131 g_free( handler->rxq ); 132 g_free( handler->cmd_text ); 133 134 handler->rxlen = 0; 135 handler->rxq = NULL; 136 handler->cmd_text = NULL; 137 } 138 85 139 static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond ) 86 140 { 87 struct im_connection *ic= data;88 struct msn_data *md = ic->proto_data;89 90 if( msn_handler( md->handler ) == -1 ) /* Don't do this on ret == 0, it's already done then. */141 struct msn_handler_data *handler = data; 142 struct im_connection *ic = handler->data; 143 144 if( msn_handler( handler ) == -1 ) /* Don't do this on ret == 0, it's already done then. */ 91 145 { 92 146 imcb_error( ic, "Error while reading from server" ); … … 99 153 } 100 154 101 static int msn_ns_command( gpointer data, char **cmd, int num_parts )102 { 103 struct im_connection *ic = data;155 static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num_parts ) 156 { 157 struct im_connection *ic = handler->data; 104 158 struct msn_data *md = ic->proto_data; 105 char buf[1024];106 159 107 160 if( num_parts == 0 ) … … 113 166 if( strcmp( cmd[0], "VER" ) == 0 ) 114 167 { 115 if( cmd[2] && strncmp( cmd[2], "MSNP8", 5 ) != 0 )168 if( cmd[2] && strncmp( cmd[2], MSNP_VER, 5 ) != 0 ) 116 169 { 117 170 imcb_error( ic, "Unsupported protocol" ); … … 120 173 } 121 174 122 g_snprintf( buf, sizeof( buf ), "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n", 123 ++md->trId, ic->acc->user ); 124 return( msn_write( ic, buf, strlen( buf ) ) ); 175 return( msn_ns_write( ic, handler->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n", 176 ++md->trId, ic->acc->user ) ); 125 177 } 126 178 else if( strcmp( cmd[0], "CVR" ) == 0 ) 127 179 { 128 180 /* We don't give a damn about the information we just received */ 129 g_snprintf( buf, sizeof( buf ), "USR %d TWN I %s\r\n", ++md->trId, ic->acc->user ); 130 return( msn_write( ic, buf, strlen( buf ) ) ); 181 return msn_ns_write( ic, handler->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user ); 131 182 } 132 183 else if( strcmp( cmd[0], "XFR" ) == 0 ) … … 135 186 int port; 136 187 137 if( num_parts == 6 && strcmp( cmd[2], "NS" ) == 0 ) 138 { 139 b_event_remove( ic->inpa ); 140 ic->inpa = 0; 141 closesocket( md->fd ); 188 if( num_parts >= 6 && strcmp( cmd[2], "NS" ) == 0 ) 189 { 190 b_event_remove( handler->inpa ); 191 handler->inpa = -1; 142 192 143 193 server = strchr( cmd[3], ':' ); … … 153 203 154 204 imcb_log( ic, "Transferring to other server" ); 155 156 md->fd = proxy_connect( server, port, msn_ns_connected, ic ); 157 } 158 else if( num_parts == 6 && strcmp( cmd[2], "SB" ) == 0 ) 205 return msn_ns_connect( ic, handler, server, port ); 206 } 207 else if( num_parts >= 6 && strcmp( cmd[2], "SB" ) == 0 ) 159 208 { 160 209 struct msn_switchboard *sb; … … 220 269 else if( strcmp( cmd[0], "USR" ) == 0 ) 221 270 { 222 if( num_parts == 5 && strcmp( cmd[2], "TWN" ) == 0 && strcmp( cmd[3], "S" ) == 0 ) 223 { 224 /* Time for some Passport black magic... */ 225 if( !passport_get_token( msn_auth_got_passport_token, ic, ic->acc->user, ic->acc->pass, cmd[4] ) ) 226 { 227 imcb_error( ic, "Error while contacting Passport server" ); 228 imc_logout( ic, TRUE ); 229 return( 0 ); 230 } 231 } 232 else if( num_parts >= 7 && strcmp( cmd[2], "OK" ) == 0 ) 233 { 234 if( num_parts == 7 ) 235 msn_ns_got_display_name( ic, cmd[4] ); 236 else 237 imcb_log( ic, "Warning: Friendly name in server response was corrupted" ); 238 271 if( num_parts >= 6 && strcmp( cmd[2], "SSO" ) == 0 && 272 strcmp( cmd[3], "S" ) == 0 ) 273 { 274 g_free( md->pp_policy ); 275 md->pp_policy = g_strdup( cmd[4] ); 276 msn_soap_passport_sso_request( ic, cmd[5] ); 277 } 278 else if( strcmp( cmd[2], "OK" ) == 0 ) 279 { 239 280 imcb_log( ic, "Authenticated, getting buddy list" ); 240 241 g_snprintf( buf, sizeof( buf ), "SYN %d 0\r\n", ++md->trId ); 242 return( msn_write( ic, buf, strlen( buf ) ) ); 281 msn_soap_memlist_request( ic ); 243 282 } 244 283 else … … 251 290 else if( strcmp( cmd[0], "MSG" ) == 0 ) 252 291 { 253 if( num_parts != 4 ) 254 { 255 imcb_error( ic, "Syntax error" ); 256 imc_logout( ic, TRUE ); 257 return( 0 ); 258 } 259 260 md->handler->msglen = atoi( cmd[3] ); 261 262 if( md->handler->msglen <= 0 ) 263 { 264 imcb_error( ic, "Syntax error" ); 265 imc_logout( ic, TRUE ); 266 return( 0 ); 267 } 268 } 269 else if( strcmp( cmd[0], "SYN" ) == 0 ) 270 { 271 if( num_parts == 5 ) 272 { 273 int i, groupcount; 274 275 groupcount = atoi( cmd[4] ); 276 if( groupcount > 0 ) 277 { 278 /* valgrind says this is leaking memory, I'm guessing 279 that this happens during server redirects. */ 280 if( md->grouplist ) 281 { 282 for( i = 0; i < md->groupcount; i ++ ) 283 g_free( md->grouplist[i] ); 284 g_free( md->grouplist ); 285 } 286 287 md->groupcount = groupcount; 288 md->grouplist = g_new0( char *, md->groupcount ); 289 } 290 291 md->buddycount = atoi( cmd[3] ); 292 if( !*cmd[3] || md->buddycount == 0 ) 293 msn_logged_in( ic ); 294 } 295 else 296 { 297 /* Hrrm... This SYN reply doesn't really look like something we expected. 298 Let's assume everything is okay. */ 299 300 msn_logged_in( ic ); 301 } 302 } 303 else if( strcmp( cmd[0], "LST" ) == 0 ) 304 { 305 int list; 306 307 if( num_parts != 4 && num_parts != 5 ) 308 { 309 imcb_error( ic, "Syntax error" ); 310 imc_logout( ic, TRUE ); 311 return( 0 ); 312 } 313 314 http_decode( cmd[2] ); 315 list = atoi( cmd[3] ); 316 317 if( list & 1 ) /* FL */ 318 { 319 char *group = NULL; 320 int num; 321 322 if( cmd[4] != NULL && sscanf( cmd[4], "%d", &num ) == 1 && num < md->groupcount ) 323 group = md->grouplist[num]; 324 325 imcb_add_buddy( ic, cmd[1], group ); 326 imcb_rename_buddy( ic, cmd[1], cmd[2] ); 327 } 328 if( list & 2 ) /* AL */ 329 { 330 ic->permit = g_slist_append( ic->permit, g_strdup( cmd[1] ) ); 331 } 332 if( list & 4 ) /* BL */ 333 { 334 ic->deny = g_slist_append( ic->deny, g_strdup( cmd[1] ) ); 335 } 336 if( list & 8 ) /* RL */ 337 { 338 if( ( list & 6 ) == 0 ) 339 msn_buddy_ask( ic, cmd[1], cmd[2] ); 340 } 341 342 if( --md->buddycount == 0 ) 343 { 344 if( ic->flags & OPT_LOGGED_IN ) 345 { 346 imcb_log( ic, "Successfully transferred to different server" ); 347 g_snprintf( buf, sizeof( buf ), "CHG %d %s %d\r\n", ++md->trId, md->away_state->code, 0 ); 348 return( msn_write( ic, buf, strlen( buf ) ) ); 349 } 350 else 351 { 352 msn_logged_in( ic ); 353 } 354 } 355 } 356 else if( strcmp( cmd[0], "LSG" ) == 0 ) 357 { 358 int num; 359 360 if( num_parts != 4 ) 361 { 362 imcb_error( ic, "Syntax error" ); 363 imc_logout( ic, TRUE ); 364 return( 0 ); 365 } 366 367 http_decode( cmd[2] ); 368 num = atoi( cmd[1] ); 369 370 if( num < md->groupcount ) 371 md->grouplist[num] = g_strdup( cmd[2] ); 292 if( num_parts < 4 ) 293 { 294 imcb_error( ic, "Syntax error" ); 295 imc_logout( ic, TRUE ); 296 return( 0 ); 297 } 298 299 handler->msglen = atoi( cmd[3] ); 300 301 if( handler->msglen <= 0 ) 302 { 303 imcb_error( ic, "Syntax error" ); 304 imc_logout( ic, TRUE ); 305 return( 0 ); 306 } 307 } 308 else if( strcmp( cmd[0], "BLP" ) == 0 ) 309 { 310 msn_ns_send_adl_start( ic ); 311 return msn_ns_finish_login( ic ); 312 } 313 else if( strcmp( cmd[0], "ADL" ) == 0 ) 314 { 315 if( num_parts >= 3 && strcmp( cmd[2], "OK" ) == 0 ) 316 { 317 msn_ns_send_adl( ic ); 318 return msn_ns_finish_login( ic ); 319 } 320 else if( num_parts >= 3 ) 321 { 322 handler->msglen = atoi( cmd[2] ); 323 } 324 } 325 else if( strcmp( cmd[0], "PRP" ) == 0 ) 326 { 327 imcb_connected( ic ); 372 328 } 373 329 else if( strcmp( cmd[0], "CHL" ) == 0 ) 374 330 { 375 md5_state_t state; 376 md5_byte_t digest[16]; 377 int i; 378 379 if( num_parts != 3 ) 380 { 381 imcb_error( ic, "Syntax error" ); 382 imc_logout( ic, TRUE ); 383 return( 0 ); 384 } 385 386 md5_init( &state ); 387 md5_append( &state, (const md5_byte_t *) cmd[2], strlen( cmd[2] ) ); 388 md5_append( &state, (const md5_byte_t *) QRY_CODE, strlen( QRY_CODE ) ); 389 md5_finish( &state, digest ); 390 391 g_snprintf( buf, sizeof( buf ), "QRY %d %s %d\r\n", ++md->trId, QRY_NAME, 32 ); 392 for( i = 0; i < 16; i ++ ) 393 g_snprintf( buf + strlen( buf ), 3, "%02x", digest[i] ); 394 395 return( msn_write( ic, buf, strlen( buf ) ) ); 331 char *resp; 332 int st; 333 334 if( num_parts < 3 ) 335 { 336 imcb_error( ic, "Syntax error" ); 337 imc_logout( ic, TRUE ); 338 return( 0 ); 339 } 340 341 resp = msn_p11_challenge( cmd[2] ); 342 343 st = msn_ns_write( ic, -1, "QRY %d %s %zd\r\n%s", 344 ++md->trId, MSNP11_PROD_ID, 345 strlen( resp ), resp ); 346 g_free( resp ); 347 return st; 396 348 } 397 349 else if( strcmp( cmd[0], "ILN" ) == 0 ) … … 399 351 const struct msn_away_state *st; 400 352 401 if( num_parts !=6 )402 { 403 imcb_error( ic, "Syntax error" ); 404 imc_logout( ic, TRUE ); 405 return( 0 ); 406 } 407 408 http_decode( cmd[ 4] );409 imcb_rename_buddy( ic, cmd[3], cmd[ 4] );353 if( num_parts < 6 ) 354 { 355 imcb_error( ic, "Syntax error" ); 356 imc_logout( ic, TRUE ); 357 return( 0 ); 358 } 359 360 http_decode( cmd[5] ); 361 imcb_rename_buddy( ic, cmd[3], cmd[5] ); 410 362 411 363 st = msn_away_state_by_code( cmd[2] ); … … 432 384 { 433 385 const struct msn_away_state *st; 434 435 if( num_parts != 5 ) 436 { 437 imcb_error( ic, "Syntax error" ); 438 imc_logout( ic, TRUE ); 439 return( 0 ); 440 } 441 442 http_decode( cmd[3] ); 443 imcb_rename_buddy( ic, cmd[2], cmd[3] ); 386 int cap; 387 388 if( num_parts < 6 ) 389 { 390 imcb_error( ic, "Syntax error" ); 391 imc_logout( ic, TRUE ); 392 return( 0 ); 393 } 394 395 http_decode( cmd[4] ); 396 cap = atoi( cmd[5] ); 397 imcb_rename_buddy( ic, cmd[2], cmd[4] ); 444 398 445 399 st = msn_away_state_by_code( cmd[1] ); … … 451 405 452 406 imcb_buddy_status( ic, cmd[2], OPT_LOGGED_IN | 453 ( st != msn_away_state_list ? OPT_AWAY : 0 ), 407 ( st != msn_away_state_list ? OPT_AWAY : 0 ) | 408 ( cap & 1 ? OPT_MOBILE : 0 ), 454 409 st->name, NULL ); 455 410 … … 462 417 int session, port; 463 418 464 if( num_parts !=7 )419 if( num_parts < 7 ) 465 420 { 466 421 imcb_error( ic, "Syntax error" ); … … 504 459 } 505 460 } 506 else if( strcmp( cmd[0], "ADD" ) == 0 )507 {508 if( num_parts == 6 && strcmp( cmd[2], "RL" ) == 0 )509 {510 GSList *l;511 512 http_decode( cmd[5] );513 514 if( strchr( cmd[4], '@' ) == NULL )515 {516 imcb_error( ic, "Syntax error" );517 imc_logout( ic, TRUE );518 return 0;519 }520 521 /* We got added by someone. If we don't have this522 person in permit/deny yet, inform the user. */523 for( l = ic->permit; l; l = l->next )524 if( g_strcasecmp( l->data, cmd[4] ) == 0 )525 return 1;526 527 for( l = ic->deny; l; l = l->next )528 if( g_strcasecmp( l->data, cmd[4] ) == 0 )529 return 1;530 531 msn_buddy_ask( ic, cmd[4], cmd[5] );532 }533 else if( num_parts >= 6 && strcmp( cmd[2], "FL" ) == 0 )534 {535 const char *group = NULL;536 int num;537 538 if( cmd[6] != NULL && sscanf( cmd[6], "%d", &num ) == 1 && num < md->groupcount )539 group = md->grouplist[num];540 541 http_decode( cmd[5] );542 imcb_add_buddy( ic, cmd[4], group );543 imcb_rename_buddy( ic, cmd[4], cmd[5] );544 }545 }546 461 else if( strcmp( cmd[0], "OUT" ) == 0 ) 547 462 { … … 565 480 return( 0 ); 566 481 } 482 else if( strcmp( cmd[0], "IPG" ) == 0 ) 483 { 484 imcb_error( ic, "Received IPG command, we don't handle them yet." ); 485 486 handler->msglen = atoi( cmd[1] ); 487 488 if( handler->msglen <= 0 ) 489 { 490 imcb_error( ic, "Syntax error" ); 491 imc_logout( ic, TRUE ); 492 return( 0 ); 493 } 494 } 567 495 #if 0 568 /* Discard this one completely for now since I don't care about the ack569 and since MSN servers can apparently screw up the formatting. */570 else if( strcmp( cmd[0], "REA" ) == 0 )571 {572 if( num_parts != 5 )573 {574 imcb_error( ic, "Syntax error" );575 imc_logout( ic, TRUE );576 return( 0 );577 }578 579 if( g_strcasecmp( cmd[3], ic->acc->user ) == 0 )580 {581 set_t *s;582 583 http_decode( cmd[4] );584 strncpy( ic->displayname, cmd[4], sizeof( ic->displayname ) );585 ic->displayname[sizeof(ic->displayname)-1] = 0;586 587 if( ( s = set_find( &ic->acc->set, "display_name" ) ) )588 {589 g_free( s->value );590 s->value = g_strdup( cmd[4] );591 }592 }593 else594 {595 /* This is not supposed to happen, but let's handle it anyway... */596 http_decode( cmd[4] );597 imcb_rename_buddy( ic, cmd[3], cmd[4] );598 }599 }600 #endif601 else if( strcmp( cmd[0], "IPG" ) == 0 )602 {603 imcb_error( ic, "Received IPG command, we don't handle them yet." );604 605 md->handler->msglen = atoi( cmd[1] );606 607 if( md->handler->msglen <= 0 )608 {609 imcb_error( ic, "Syntax error" );610 imc_logout( ic, TRUE );611 return( 0 );612 }613 }614 496 else if( strcmp( cmd[0], "ADG" ) == 0 ) 615 497 { … … 656 538 } 657 539 } 540 #endif 541 else if( strcmp( cmd[0], "GCF" ) == 0 ) 542 { 543 /* Coming up is cmd[2] bytes of stuff we're supposed to 544 censore. Meh. */ 545 handler->msglen = atoi( cmd[2] ); 546 } 547 else if( strcmp( cmd[0], "UBX" ) == 0 ) 548 { 549 /* Status message. */ 550 if( num_parts >= 4 ) 551 handler->msglen = atoi( cmd[3] ); 552 } 553 else if( strcmp( cmd[0], "NOT" ) == 0 ) 554 { 555 /* Some kind of notification, poorly documented but 556 apparently used to announce address book changes. */ 557 if( num_parts >= 2 ) 558 handler->msglen = atoi( cmd[1] ); 559 } 658 560 else if( isdigit( cmd[0][0] ) ) 659 561 { … … 668 570 return( 0 ); 669 571 } 572 573 /* Oh yes, errors can have payloads too now. Discard them for now. */ 574 if( num_parts >= 3 ) 575 handler->msglen = atoi( cmd[2] ); 670 576 } 671 577 else … … 677 583 } 678 584 679 static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts )680 { 681 struct im_connection *ic = data;585 static int msn_ns_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts ) 586 { 587 struct im_connection *ic = handler->data; 682 588 char *body; 683 589 int blen = 0; … … 765 671 } 766 672 } 673 else if( strcmp( cmd[0], "UBX" ) == 0 ) 674 { 675 struct xt_node *psm; 676 char *psm_text = NULL; 677 678 psm = xt_from_string( msg ); 679 if( psm && strcmp( psm->name, "Data" ) == 0 && 680 ( psm = xt_find_node( psm->children, "PSM" ) ) ) 681 psm_text = psm->text; 682 683 imcb_buddy_status_msg( ic, cmd[1], psm_text ); 684 xt_free_node( psm ); 685 } 686 else if( strcmp( cmd[0], "ADL" ) == 0 ) 687 { 688 struct xt_node *adl, *d, *c; 689 690 if( !( adl = xt_from_string( msg ) ) ) 691 return 1; 692 693 for( d = adl->children; d; d = d->next ) 694 { 695 char *dn; 696 if( strcmp( d->name, "d" ) != 0 || 697 ( dn = xt_find_attr( d, "n" ) ) == NULL ) 698 continue; 699 for( c = d->children; c; c = c->next ) 700 { 701 bee_user_t *bu; 702 struct msn_buddy_data *bd; 703 char *cn, *handle, *f, *l; 704 int flags; 705 706 if( strcmp( c->name, "c" ) != 0 || 707 ( l = xt_find_attr( c, "l" ) ) == NULL || 708 ( cn = xt_find_attr( c, "n" ) ) == NULL ) 709 continue; 710 711 handle = g_strdup_printf( "%s@%s", cn, dn ); 712 if( !( ( bu = bee_user_by_handle( ic->bee, ic, handle ) ) || 713 ( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) ) ) 714 { 715 g_free( handle ); 716 continue; 717 } 718 g_free( handle ); 719 bd = bu->data; 720 721 if( ( f = xt_find_attr( c, "f" ) ) ) 722 { 723 http_decode( f ); 724 imcb_rename_buddy( ic, bu->handle, f ); 725 } 726 727 flags = atoi( l ) & 15; 728 if( bd->flags != flags ) 729 { 730 bd->flags = flags; 731 msn_buddy_ask( bu ); 732 } 733 } 734 } 735 } 767 736 768 737 return( 1 ); 769 738 } 770 739 771 static void msn_auth_got_passport_token( struct msn_auth_data *mad ) 772 { 773 struct im_connection *ic = mad->data; 740 void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error ) 741 { 774 742 struct msn_data *md; 775 743 … … 779 747 780 748 md = ic->proto_data; 781 if( mad->token ) 782 { 783 char buf[1024]; 784 785 g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, mad->token ); 786 msn_write( ic, buf, strlen( buf ) ); 749 750 if( token ) 751 { 752 msn_ns_write( ic, -1, "USR %d SSO S %s %s\r\n", ++md->trId, md->tokens[0], token ); 787 753 } 788 754 else 789 755 { 790 imcb_error( ic, "Error during Passport authentication: %s", mad->error );756 imcb_error( ic, "Error during Passport authentication: %s", error ); 791 757 imc_logout( ic, TRUE ); 792 758 } 793 759 } 794 760 795 static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name ) 796 { 797 set_t *s; 798 799 if( ( s = set_find( &ic->acc->set, "display_name" ) ) == NULL ) 800 return FALSE; /* Shouldn't happen.. */ 801 802 http_decode( name ); 803 804 if( s->value && strcmp( s->value, name ) == 0 ) 805 { 806 return TRUE; 807 /* The names match, nothing to worry about. */ 808 } 809 else if( s->value != NULL && 810 ( strcmp( name, ic->acc->user ) == 0 || 811 set_getbool( &ic->acc->set, "local_display_name" ) ) ) 812 { 813 /* The server thinks our display name is our e-mail address 814 which is probably wrong, or the user *wants* us to do this: 815 Always use the locally set display_name. */ 816 return msn_set_display_name( ic, s->value ); 817 } 761 void msn_auth_got_contact_list( struct im_connection *ic ) 762 { 763 struct msn_data *md; 764 765 /* Dead connection? */ 766 if( g_slist_find( msn_connections, ic ) == NULL ) 767 return; 768 769 md = ic->proto_data; 770 msn_ns_write( ic, -1, "BLP %d %s\r\n", ++md->trId, "BL" ); 771 } 772 773 static gboolean msn_ns_send_adl_1( gpointer key, gpointer value, gpointer data ) 774 { 775 struct xt_node *adl = data, *d, *c; 776 struct bee_user *bu = value; 777 struct msn_buddy_data *bd = bu->data; 778 struct msn_data *md = bu->ic->proto_data; 779 char handle[strlen(bu->handle)]; 780 char *domain; 781 char l[4]; 782 783 if( ( bd->flags & 7 ) == 0 || ( bd->flags & MSN_BUDDY_ADL_SYNCED ) ) 784 return FALSE; 785 786 strcpy( handle, bu->handle ); 787 if( ( domain = strchr( handle, '@' ) ) == NULL ) /* WTF */ 788 return FALSE; 789 *domain = '\0'; 790 domain ++; 791 792 if( ( d = adl->children ) == NULL || 793 g_strcasecmp( xt_find_attr( d, "n" ), domain ) != 0 ) 794 { 795 d = xt_new_node( "d", NULL, NULL ); 796 xt_add_attr( d, "n", domain ); 797 xt_insert_child( adl, d ); 798 } 799 800 g_snprintf( l, sizeof( l ), "%d", bd->flags & 7 ); 801 c = xt_new_node( "c", NULL, NULL ); 802 xt_add_attr( c, "n", handle ); 803 xt_add_attr( c, "l", l ); 804 xt_add_attr( c, "t", "1" ); /* 1 means normal, 4 means mobile? */ 805 xt_insert_child( d, c ); 806 807 /* Do this in batches of 100. */ 808 bd->flags |= MSN_BUDDY_ADL_SYNCED; 809 return (--md->adl_todo % 140) == 0; 810 } 811 812 static void msn_ns_send_adl( struct im_connection *ic ) 813 { 814 struct xt_node *adl; 815 struct msn_data *md = ic->proto_data; 816 char *adls; 817 818 adl = xt_new_node( "ml", NULL, NULL ); 819 xt_add_attr( adl, "l", "1" ); 820 g_tree_foreach( md->domaintree, msn_ns_send_adl_1, adl ); 821 if( adl->children == NULL ) 822 { 823 /* This tells the caller that we're done now. */ 824 md->adl_todo = -1; 825 xt_free_node( adl ); 826 return; 827 } 828 829 adls = xt_to_string( adl ); 830 msn_ns_write( ic, -1, "ADL %d %zd\r\n%s", ++md->trId, strlen( adls ), adls ); 831 g_free( adls ); 832 } 833 834 static void msn_ns_send_adl_start( struct im_connection *ic ) 835 { 836 struct msn_data *md; 837 GSList *l; 838 839 /* Dead connection? */ 840 if( g_slist_find( msn_connections, ic ) == NULL ) 841 return; 842 843 md = ic->proto_data; 844 md->adl_todo = 0; 845 for( l = ic->bee->users; l; l = l->next ) 846 { 847 bee_user_t *bu = l->data; 848 struct msn_buddy_data *bd = bu->data; 849 850 if( bu->ic != ic || ( bd->flags & 7 ) == 0 ) 851 continue; 852 853 bd->flags &= ~MSN_BUDDY_ADL_SYNCED; 854 md->adl_todo++; 855 } 856 857 msn_ns_send_adl( ic ); 858 } 859 860 int msn_ns_finish_login( struct im_connection *ic ) 861 { 862 struct msn_data *md = ic->proto_data; 863 864 if( ic->flags & OPT_LOGGED_IN ) 865 return 1; 866 867 if( md->adl_todo < 0 ) 868 md->flags |= MSN_DONE_ADL; 869 870 if( ( md->flags & MSN_DONE_ADL ) && ( md->flags & MSN_GOT_PROFILE ) ) 871 return msn_ns_set_display_name( ic, set_getstr( &ic->acc->set, "display_name" ) ); 818 872 else 819 { 820 if( s->value && *s->value ) 821 imcb_log( ic, "BitlBee thinks your display name is `%s' but " 822 "the MSN server says it's `%s'. Using the MSN " 823 "server's name. Set local_display_name to true " 824 "to use the local name.", s->value, name ); 825 826 if( g_utf8_validate( name, -1, NULL ) ) 827 { 828 g_free( s->value ); 829 s->value = g_strdup( name ); 830 } 831 else 832 { 833 imcb_log( ic, "Warning: Friendly name in server response was corrupted" ); 834 } 835 836 return TRUE; 837 } 838 } 873 return 1; 874 } -
protocols/msn/sb.c
r88de0c9 r8e9e2b7 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-20 05Wilmer van der Gaast and others *4 * Copyright 2002-2010 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 27 27 #include "nogaim.h" 28 28 #include "msn.h" 29 #include "passport.h"30 29 #include "md5.h" 30 #include "soap.h" 31 31 #include "invitation.h" 32 32 33 33 static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond ); 34 static int msn_sb_command( gpointer data, char **cmd, int num_parts ); 35 static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); 36 37 int msn_sb_write( struct msn_switchboard *sb, char *s, int len ) 38 { 34 static int msn_sb_command( struct msn_handler_data *handler, char **cmd, int num_parts ); 35 static int msn_sb_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts ); 36 37 int msn_sb_write( struct msn_switchboard *sb, const char *fmt, ... ) 38 { 39 va_list params; 40 char *out; 41 size_t len; 39 42 int st; 40 43 41 st = write( sb->fd, s, len ); 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 ); 42 54 if( st != len ) 43 55 { 44 56 msn_sb_destroy( sb ); 45 return ( 0 );46 } 47 48 return ( 1 );57 return 0; 58 } 59 60 return 1; 49 61 } 50 62 … … 53 65 struct msn_data *md = ic->proto_data; 54 66 struct msn_switchboard *sb; 55 char buf[1024];56 67 57 68 /* FIXME: *CHECK* the reliability of using spare sb's! */ … … 61 72 62 73 sb->who = g_strdup( m->who ); 63 g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, m->who ); 64 if( msn_sb_write( sb, buf, strlen( buf ) ) ) 74 if( msn_sb_write( sb, "CAL %d %s\r\n", ++sb->trId, m->who ) ) 65 75 { 66 76 /* He/She should join the switchboard soon, let's queue the message. */ … … 73 83 74 84 /* If we reach this line, there was no spare switchboard, so let's make one. */ 75 g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId ); 76 if( !msn_write( ic, buf, strlen( buf ) ) ) 85 if( !msn_ns_write( ic, -1, "XFR %d SB\r\n", ++md->trId ) ) 77 86 { 78 87 g_free( m->who ); … … 165 174 if( sb->ready ) 166 175 { 167 char * packet, *buf;176 char *buf; 168 177 int i, j; 169 178 … … 201 210 202 211 /* Build the final packet (MSG command + the message). */ 203 packet = g_strdup_printf( "MSG %d N %d\r\n%s", ++sb->trId, i, buf ); 204 g_free( buf ); 205 if( msn_sb_write( sb, packet, strlen( packet ) ) ) 206 { 207 g_free( packet ); 208 return( 1 ); 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; 209 216 } 210 217 else 211 218 { 212 g_free( packet);213 return ( 0 );219 g_free( buf ); 220 return 0; 214 221 } 215 222 } … … 326 333 g_snprintf( buf, sizeof( buf ), "ANS %d %s %s %d\r\n", ++sb->trId, ic->acc->user, sb->key, sb->session ); 327 334 328 if( msn_sb_write( sb, buf, strlen( buf )) )335 if( msn_sb_write( sb, "%s", buf ) ) 329 336 sb->inp = b_input_add( sb->fd, B_EV_IO_READ, msn_sb_callback, sb ); 330 337 else … … 346 353 { 347 354 time_t now = time( NULL ); 348 char buf[1024];349 355 350 356 if( now - md->first_sb_failure > 600 ) … … 378 384 debug( "Moved queued messages back to the main queue, " 379 385 "creating a new switchboard to retry." ); 380 g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId ); 381 if( !msn_write( ic, buf, strlen( buf ) ) ) 386 if( !msn_ns_write( ic, -1, "XFR %d SB\r\n", ++md->trId ) ) 382 387 return FALSE; 383 388 } … … 387 392 } 388 393 389 static int msn_sb_command( gpointer data, char **cmd, int num_parts )390 { 391 struct msn_switchboard *sb = data;394 static int msn_sb_command( struct msn_handler_data *handler, char **cmd, int num_parts ) 395 { 396 struct msn_switchboard *sb = handler->data; 392 397 struct im_connection *ic = sb->ic; 393 char buf[1024];394 398 395 399 if( !num_parts ) … … 407 411 else if( strcmp( cmd[0], "USR" ) == 0 ) 408 412 { 409 if( num_parts !=5 )413 if( num_parts < 5 ) 410 414 { 411 415 msn_sb_destroy( sb ); … … 420 424 421 425 if( sb->who ) 422 { 423 g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, sb->who ); 424 return( msn_sb_write( sb, buf, strlen( buf ) ) ); 425 } 426 return msn_sb_write( sb, "CAL %d %s\r\n", ++sb->trId, sb->who ); 426 427 else 427 {428 428 debug( "Just created a switchboard, but I don't know what to do with it." ); 429 }430 429 } 431 430 else if( strcmp( cmd[0], "IRO" ) == 0 ) … … 433 432 int num, tot; 434 433 435 if( num_parts !=6 )434 if( num_parts < 6 ) 436 435 { 437 436 msn_sb_destroy( sb ); … … 470 469 else if( strcmp( cmd[0], "ANS" ) == 0 ) 471 470 { 472 if( num_parts !=3 )471 if( num_parts < 3 ) 473 472 { 474 473 msn_sb_destroy( sb ); … … 489 488 else if( strcmp( cmd[0], "CAL" ) == 0 ) 490 489 { 491 if( num_parts !=4 || !isdigit( cmd[3][0] ) )490 if( num_parts < 4 || !isdigit( cmd[3][0] ) ) 492 491 { 493 492 msn_sb_destroy( sb ); … … 499 498 else if( strcmp( cmd[0], "JOI" ) == 0 ) 500 499 { 501 if( num_parts !=3 )500 if( num_parts < 3 ) 502 501 { 503 502 msn_sb_destroy( sb ); … … 560 559 else if( strcmp( cmd[0], "MSG" ) == 0 ) 561 560 { 562 if( num_parts !=4 )561 if( num_parts < 4 ) 563 562 { 564 563 msn_sb_destroy( sb ); … … 625 624 const struct msn_status_code *err = msn_status_by_number( num ); 626 625 627 imcb_error( ic, "Error reported by switchboard server: %s", err->text ); 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 ); 628 632 629 633 if( err->flags & STATUS_SB_FATAL ) … … 661 665 } 662 666 663 static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts )664 { 665 struct msn_switchboard *sb = data;667 static 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; 666 670 struct im_connection *ic = sb->ic; 667 671 char *body; … … 741 745 else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 ) 742 746 { 743 imcb_error( sb->ic, "Cannot receive file from %s: BitlBee does not "744 "support msnmsgrp2p yet.", sb->who );747 /* Not currently implemented. Don't warn about it since 748 this seems to be used for avatars now. */ 745 749 g_free( ct ); 746 750 } -
protocols/msn/tables.c
r88de0c9 r8e9e2b7 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-20 04Wilmer van der Gaast and others *4 * Copyright 2002-2010 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 83 83 { 230, "Cannot remove that group", 0 }, 84 84 { 231, "Invalid group", 0 }, 85 { 240, "ADL/RML command with corrupted payload", STATUS_FATAL }, 86 { 241, "ADL/RML command with invalid modification", 0 }, 85 87 { 280, "Switchboard failed", STATUS_SB_FATAL }, 86 88 { 281, "Transfer to switchboard failed", 0 },
Note: See TracChangeset
for help on using the changeset viewer.