Changeset 5ebff60 for protocols/msn
- Timestamp:
- 2015-02-20T22:50:54Z (10 years ago)
- Branches:
- master
- Children:
- 0b9daac, 3d45471, 7733b8c
- Parents:
- af359b4
- git-author:
- Indent <please@…> (19-02-15 05:47:20)
- git-committer:
- dequis <dx@…> (20-02-15 22:50:54)
- Location:
- protocols/msn
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/msn/invitation.c
raf359b4 r5ebff60 13 13 the Free Software Foundation; either version 2 of the License, or 14 14 (at your option) any later version. 15 15 16 16 This program is distributed in the hope that it will be useful, 17 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 19 GNU General Public License for more details. 20 20 21 21 You should have received a copy of the GNU General Public License with 22 22 the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; … … 33 33 #undef debug 34 34 #endif 35 #define debug(msg ...) log_message( LOGLVL_INFO, msg)36 37 static void msn_ftp_free( file_transfer_t *file);38 static void msn_ftpr_accept( file_transfer_t *file);39 static void msn_ftp_finished( file_transfer_t *file);40 static void msn_ftp_canceled( file_transfer_t *file, char *reason);41 static gboolean msn_ftpr_write_request( file_transfer_t *file);42 43 static gboolean msn_ftp_connected( gpointer data, gint fd, b_input_condition cond);44 static gboolean msn_ftp_read( gpointer data, gint fd, b_input_condition cond);45 gboolean msn_ftps_write( file_transfer_t *file, char *buffer, unsigned int len);35 #define debug(msg ...) log_message(LOGLVL_INFO, msg) 36 37 static void msn_ftp_free(file_transfer_t *file); 38 static void msn_ftpr_accept(file_transfer_t *file); 39 static void msn_ftp_finished(file_transfer_t *file); 40 static void msn_ftp_canceled(file_transfer_t *file, char *reason); 41 static gboolean msn_ftpr_write_request(file_transfer_t *file); 42 43 static gboolean msn_ftp_connected(gpointer data, gint fd, b_input_condition cond); 44 static gboolean msn_ftp_read(gpointer data, gint fd, b_input_condition cond); 45 gboolean msn_ftps_write(file_transfer_t *file, char *buffer, unsigned int len); 46 46 47 47 /* 48 48 * Vararg wrapper for imcb_file_canceled(). 49 49 */ 50 gboolean msn_ftp_abort( file_transfer_t *file, char *format, ... ) 51 { 52 va_list params; 53 va_start( params, format ); 54 char error[128]; 55 56 if( vsnprintf( error, 128, format, params ) < 0 ) 57 sprintf( error, "internal error parsing error string (BUG)" ); 58 va_end( params ); 59 imcb_file_canceled( file, error ); 50 gboolean msn_ftp_abort(file_transfer_t *file, char *format, ...) 51 { 52 va_list params; 53 54 va_start(params, format); 55 char error[128]; 56 57 if (vsnprintf(error, 128, format, params) < 0) { 58 sprintf(error, "internal error parsing error string (BUG)"); 59 } 60 va_end(params); 61 imcb_file_canceled(file, error); 60 62 return FALSE; 61 63 } … … 63 65 /* very useful */ 64 66 #define ASSERTSOCKOP(op, msg) \ 65 if ( (op) == -1 )\66 return msn_ftp_abort( file , msg ": %s", strerror( errno ) );67 68 void msn_ftp_invitation_cmd( 69 char *trailer)70 { 71 struct msn_message *m = g_new0( struct msn_message, 1);72 73 m->text = g_strdup_printf( 74 75 76 77 78 79 80 81 82 m->who = g_strdup( who);83 84 msn_sb_write_msg( ic, m);85 } 86 87 void msn_ftp_cancel_invite( struct im_connection *ic, char *who, int cookie, char *code)67 if ((op) == -1) { \ 68 return msn_ftp_abort(file, msg ": %s", strerror(errno)); } 69 70 void msn_ftp_invitation_cmd(struct im_connection *ic, char *who, int cookie, char *icmd, 71 char *trailer) 72 { 73 struct msn_message *m = g_new0(struct msn_message, 1); 74 75 m->text = g_strdup_printf("%s" 76 "Invitation-Command: %s\r\n" 77 "Invitation-Cookie: %u\r\n" 78 "%s", 79 MSN_INVITE_HEADERS, 80 icmd, 81 cookie, 82 trailer); 83 84 m->who = g_strdup(who); 85 86 msn_sb_write_msg(ic, m); 87 } 88 89 void msn_ftp_cancel_invite(struct im_connection *ic, char *who, int cookie, char *code) 88 90 { 89 91 char buf[64]; 90 92 91 g_snprintf( buf, sizeof( buf ), "Cancel-Code: %s\r\n", code);92 msn_ftp_invitation_cmd( ic, who, cookie, "CANCEL", buf);93 } 94 95 void msn_ftp_transfer_request( struct im_connection *ic, file_transfer_t *file, char *who)96 { 97 unsigned int cookie = time( NULL );/* TODO: randomize */93 g_snprintf(buf, sizeof(buf), "Cancel-Code: %s\r\n", code); 94 msn_ftp_invitation_cmd(ic, who, cookie, "CANCEL", buf); 95 } 96 97 void msn_ftp_transfer_request(struct im_connection *ic, file_transfer_t *file, char *who) 98 { 99 unsigned int cookie = time(NULL); /* TODO: randomize */ 98 100 char buf[2048]; 99 101 100 msn_filetransfer_t *msn_file = g_new0( msn_filetransfer_t, 1 ); 102 msn_filetransfer_t *msn_file = g_new0(msn_filetransfer_t, 1); 103 101 104 file->data = msn_file; 102 105 file->free = msn_ftp_free; … … 105 108 msn_file->md = ic->proto_data; 106 109 msn_file->invite_cookie = cookie; 107 msn_file->handle = g_strdup( who);110 msn_file->handle = g_strdup(who); 108 111 msn_file->dcc = file; 109 msn_file->md->filetransfers = g_slist_prepend( msn_file->md->filetransfers, msn_file->dcc);112 msn_file->md->filetransfers = g_slist_prepend(msn_file->md->filetransfers, msn_file->dcc); 110 113 msn_file->fd = -1; 111 114 msn_file->sbufpos = 3; 112 115 113 g_snprintf( buf, sizeof( buf ),114 115 116 117 118 119 120 121 msn_ftp_invitation_cmd( msn_file->md->ic, msn_file->handle, cookie, "INVITE", buf);122 123 imcb_file_recv_start( file);124 } 125 126 void msn_invitation_invite( struct msn_switchboard *sb, char *handle, unsigned int cookie, char *body, int blen)127 { 128 char *itype = msn_findheader( body, "Application-GUID:", blen);116 g_snprintf(buf, sizeof(buf), 117 "Application-Name: File Transfer\r\n" 118 "Application-GUID: {5D3E02AB-6190-11d3-BBBB-00C04F795683}\r\n" 119 "Application-File: %s\r\n" 120 "Application-FileSize: %zd\r\n", 121 file->file_name, 122 file->file_size); 123 124 msn_ftp_invitation_cmd(msn_file->md->ic, msn_file->handle, cookie, "INVITE", buf); 125 126 imcb_file_recv_start(file); 127 } 128 129 void msn_invitation_invite(struct msn_switchboard *sb, char *handle, unsigned int cookie, char *body, int blen) 130 { 131 char *itype = msn_findheader(body, "Application-GUID:", blen); 129 132 char *name, *size, *invitecookie, *reject = NULL; 130 133 user_t *u; 131 134 size_t isize; 132 135 file_transfer_t *file; 133 134 if ( !itype || strcmp( itype, "{5D3E02AB-6190-11d3-BBBB-00C04F795683}" ) != 0) {136 137 if (!itype || strcmp(itype, "{5D3E02AB-6190-11d3-BBBB-00C04F795683}") != 0) { 135 138 /* Don't know what that is - don't care */ 136 char *iname = msn_findheader( body, "Application-Name:", blen);137 imcb_log( 138 itype ? : "with no GUID", iname ? iname : "no application name", handle);139 g_free( iname);139 char *iname = msn_findheader(body, "Application-Name:", blen); 140 imcb_log(sb->ic, "Received unknown MSN invitation %s (%s) from %s", 141 itype ? : "with no GUID", iname ? iname : "no application name", handle); 142 g_free(iname); 140 143 reject = "REJECT_NOT_INSTALLED"; 141 } else if ( 142 !( name = msn_findheader( body, "Application-File:", blen )) ||143 !( size = msn_findheader( body, "Application-FileSize:", blen )) ||144 !( invitecookie = msn_findheader(body, "Invitation-Cookie:", blen)) ||145 !( isize = atoll( size ) ) ) {146 imcb_log( 147 148 handle, name, size, invitecookie);144 } else if ( 145 !(name = msn_findheader(body, "Application-File:", blen)) || 146 !(size = msn_findheader(body, "Application-FileSize:", blen)) || 147 !(invitecookie = msn_findheader(body, "Invitation-Cookie:", blen)) || 148 !(isize = atoll(size))) { 149 imcb_log(sb->ic, "Received corrupted transfer request from %s" 150 "(name=%s, size=%s, invitecookie=%s)", 151 handle, name, size, invitecookie); 149 152 reject = "REJECT"; 150 } else if ( !( u = user_findhandle( sb->ic, handle ) )) {151 imcb_log( 152 "is not in contact list", handle);153 } else if (!(u = user_findhandle(sb->ic, handle))) { 154 imcb_log(sb->ic, "Error in parsing transfer request, User '%s'" 155 "is not in contact list", handle); 153 156 reject = "REJECT"; 154 } else if ( !( file = imcb_file_send_start( sb->ic, handle, name, isize ) )) {155 imcb_log( 156 handle, name);157 } else if (!(file = imcb_file_send_start(sb->ic, handle, name, isize))) { 158 imcb_log(sb->ic, "Error initiating transfer for request from %s for %s", 159 handle, name); 157 160 reject = "REJECT"; 158 161 } else { 159 msn_filetransfer_t *msn_file = g_new0( msn_filetransfer_t, 1);162 msn_filetransfer_t *msn_file = g_new0(msn_filetransfer_t, 1); 160 163 file->data = msn_file; 161 164 file->accept = msn_ftpr_accept; … … 166 169 msn_file->md = sb->ic->proto_data; 167 170 msn_file->invite_cookie = cookie; 168 msn_file->handle = g_strdup( handle);171 msn_file->handle = g_strdup(handle); 169 172 msn_file->dcc = file; 170 msn_file->md->filetransfers = g_slist_prepend( msn_file->md->filetransfers, msn_file->dcc);173 msn_file->md->filetransfers = g_slist_prepend(msn_file->md->filetransfers, msn_file->dcc); 171 174 msn_file->fd = -1; 172 175 } 173 176 174 if( reject ) 175 msn_ftp_cancel_invite( sb->ic, sb->who, cookie, reject ); 176 177 g_free( name ); 178 g_free( size ); 179 g_free( invitecookie ); 180 g_free( itype ); 181 } 182 183 msn_filetransfer_t* msn_find_filetransfer( struct msn_data *md, unsigned int cookie, char *handle ) 177 if (reject) { 178 msn_ftp_cancel_invite(sb->ic, sb->who, cookie, reject); 179 } 180 181 g_free(name); 182 g_free(size); 183 g_free(invitecookie); 184 g_free(itype); 185 } 186 187 msn_filetransfer_t* msn_find_filetransfer(struct msn_data *md, unsigned int cookie, char *handle) 184 188 { 185 189 GSList *l; 186 187 for ( l = md->filetransfers; l; l = l->next) {188 msn_filetransfer_t *file = ( (file_transfer_t*) l->data)->data;189 if ( file->invite_cookie == cookie && strcmp( handle, file->handle ) == 0) {190 191 for (l = md->filetransfers; l; l = l->next) { 192 msn_filetransfer_t *file = ((file_transfer_t *) l->data)->data; 193 if (file->invite_cookie == cookie && strcmp(handle, file->handle) == 0) { 190 194 return file; 191 195 } … … 194 198 } 195 199 196 gboolean msn_ftps_connected( gpointer data, gint fd, b_input_condition cond)200 gboolean msn_ftps_connected(gpointer data, gint fd, b_input_condition cond) 197 201 { 198 202 file_transfer_t *file = data; 199 203 msn_filetransfer_t *msn_file = file->data; 200 204 struct sockaddr_storage clt_addr; 201 socklen_t ssize = sizeof( clt_addr);202 203 debug( "Connected to MSNFTP client");204 205 ASSERTSOCKOP( msn_file->fd = accept( fd, (struct sockaddr *) &clt_addr, &ssize ), "Accepting connection");206 207 closesocket( fd);205 socklen_t ssize = sizeof(clt_addr); 206 207 debug("Connected to MSNFTP client"); 208 209 ASSERTSOCKOP(msn_file->fd = accept(fd, (struct sockaddr *) &clt_addr, &ssize), "Accepting connection"); 210 211 closesocket(fd); 208 212 fd = msn_file->fd; 209 sock_make_nonblocking( fd);210 211 msn_file->r_event_id = b_input_add( fd, B_EV_IO_READ, msn_ftp_read, file);213 sock_make_nonblocking(fd); 214 215 msn_file->r_event_id = b_input_add(fd, B_EV_IO_READ, msn_ftp_read, file); 212 216 213 217 return FALSE; 214 218 } 215 219 216 void msn_invitations_accept( msn_filetransfer_t *msn_file, struct msn_switchboard *sb, char *handle, unsigned int cookie, char *body, int blen ) 220 void msn_invitations_accept(msn_filetransfer_t *msn_file, struct msn_switchboard *sb, char *handle, unsigned int cookie, 221 char *body, int blen) 217 222 { 218 223 file_transfer_t *file = msn_file->dcc; 219 224 char buf[1024]; 220 unsigned int acookie = time ( NULL);221 char host[HOST_NAME_MAX +1];225 unsigned int acookie = time(NULL); 226 char host[HOST_NAME_MAX + 1]; 222 227 char port[6]; 223 228 char *errmsg; … … 225 230 msn_file->auth_cookie = acookie; 226 231 227 if( ( msn_file->fd = ft_listen( NULL, host, port, FALSE, &errmsg ) ) == -1 ) { 228 msn_ftp_abort( file, "Failed to listen locally, check your ft_listen setting in bitlbee.conf: %s", errmsg ); 232 if ((msn_file->fd = ft_listen(NULL, host, port, FALSE, &errmsg)) == -1) { 233 msn_ftp_abort(file, "Failed to listen locally, check your ft_listen setting in bitlbee.conf: %s", 234 errmsg); 229 235 return; 230 236 } 231 237 232 msn_file->r_event_id = b_input_add( msn_file->fd, B_EV_IO_READ, msn_ftps_connected, file ); 233 234 g_snprintf( buf, sizeof( buf ), 235 "IP-Address: %s\r\n" 236 "Port: %s\r\n" 237 "AuthCookie: %d\r\n" 238 "Launch-Application: FALSE\r\n" 239 "Request-Data: IP-Address:\r\n\r\n", 240 host, 241 port, 242 msn_file->auth_cookie ); 243 244 msn_ftp_invitation_cmd( msn_file->md->ic, handle, msn_file->invite_cookie, "ACCEPT", buf ); 245 } 246 247 void msn_invitationr_accept( msn_filetransfer_t *msn_file, struct msn_switchboard *sb, char *handle, unsigned int cookie, char *body, int blen ) { 238 msn_file->r_event_id = b_input_add(msn_file->fd, B_EV_IO_READ, msn_ftps_connected, file); 239 240 g_snprintf(buf, sizeof(buf), 241 "IP-Address: %s\r\n" 242 "Port: %s\r\n" 243 "AuthCookie: %d\r\n" 244 "Launch-Application: FALSE\r\n" 245 "Request-Data: IP-Address:\r\n\r\n", 246 host, 247 port, 248 msn_file->auth_cookie); 249 250 msn_ftp_invitation_cmd(msn_file->md->ic, handle, msn_file->invite_cookie, "ACCEPT", buf); 251 } 252 253 void msn_invitationr_accept(msn_filetransfer_t *msn_file, struct msn_switchboard *sb, char *handle, unsigned int cookie, 254 char *body, int blen) 255 { 248 256 file_transfer_t *file = msn_file->dcc; 249 257 char *authcookie, *ip, *port; 250 258 251 if( !( authcookie = msn_findheader( body, "AuthCookie:", blen ) ) || 252 !( ip = msn_findheader( body, "IP-Address:", blen ) ) || 253 !( port = msn_findheader( body, "Port:", blen ) ) ) { 254 msn_ftp_abort( file, "Received invalid accept reply" ); 255 } else if( 256 ( msn_file->fd = proxy_connect( ip, atoi( port ), msn_ftp_connected, file ) ) 257 < 0 ) { 258 msn_ftp_abort( file, "Error connecting to MSN client" ); 259 } else 260 msn_file->auth_cookie = strtoul( authcookie, NULL, 10 ); 261 262 g_free( authcookie ); 263 g_free( ip ); 264 g_free( port ); 265 } 266 267 void msn_invitation_accept( struct msn_switchboard *sb, char *handle, unsigned int cookie, char *body, int blen ) 268 { 269 msn_filetransfer_t *msn_file = msn_find_filetransfer( sb->ic->proto_data, cookie, handle ); 259 if (!(authcookie = msn_findheader(body, "AuthCookie:", blen)) || 260 !(ip = msn_findheader(body, "IP-Address:", blen)) || 261 !(port = msn_findheader(body, "Port:", blen))) { 262 msn_ftp_abort(file, "Received invalid accept reply"); 263 } else if ( 264 (msn_file->fd = proxy_connect(ip, atoi(port), msn_ftp_connected, file)) 265 < 0) { 266 msn_ftp_abort(file, "Error connecting to MSN client"); 267 } else { 268 msn_file->auth_cookie = strtoul(authcookie, NULL, 10); 269 } 270 271 g_free(authcookie); 272 g_free(ip); 273 g_free(port); 274 } 275 276 void msn_invitation_accept(struct msn_switchboard *sb, char *handle, unsigned int cookie, char *body, int blen) 277 { 278 msn_filetransfer_t *msn_file = msn_find_filetransfer(sb->ic->proto_data, cookie, handle); 270 279 file_transfer_t *file = msn_file ? msn_file->dcc : NULL; 271 272 if( !msn_file ) 273 imcb_log( sb->ic, "Received invitation ACCEPT message for unknown invitation (already aborted?)" ); 274 else if( file->sending ) 275 msn_invitations_accept( msn_file, sb, handle, cookie, body, blen ); 276 else 277 msn_invitationr_accept( msn_file, sb, handle, cookie, body, blen ); 278 } 279 280 void msn_invitation_cancel( struct msn_switchboard *sb, char *handle, unsigned int cookie, char *body, int blen ) 281 { 282 msn_filetransfer_t *msn_file = msn_find_filetransfer( sb->ic->proto_data, cookie, handle ); 283 284 if( !msn_file ) 285 imcb_log( sb->ic, "Received invitation CANCEL message for unknown invitation (already aborted?)" ); 286 else 287 msn_ftp_abort( msn_file->dcc, msn_findheader( body, "Cancel-Code:", blen ) ); 288 } 289 290 int msn_ftp_write( file_transfer_t *file, char *format, ... ) 280 281 if (!msn_file) { 282 imcb_log(sb->ic, "Received invitation ACCEPT message for unknown invitation (already aborted?)"); 283 } else if (file->sending) { 284 msn_invitations_accept(msn_file, sb, handle, cookie, body, blen); 285 } else { 286 msn_invitationr_accept(msn_file, sb, handle, cookie, body, blen); 287 } 288 } 289 290 void msn_invitation_cancel(struct msn_switchboard *sb, char *handle, unsigned int cookie, char *body, int blen) 291 { 292 msn_filetransfer_t *msn_file = msn_find_filetransfer(sb->ic->proto_data, cookie, handle); 293 294 if (!msn_file) { 295 imcb_log(sb->ic, "Received invitation CANCEL message for unknown invitation (already aborted?)"); 296 } else { 297 msn_ftp_abort(msn_file->dcc, msn_findheader(body, "Cancel-Code:", blen)); 298 } 299 } 300 301 int msn_ftp_write(file_transfer_t *file, char *format, ...) 291 302 { 292 303 msn_filetransfer_t *msn_file = file->data; … … 294 305 int st; 295 306 char *s; 296 297 va_start( params, format ); 298 s = g_strdup_vprintf( format, params ); 299 va_end( params ); 300 301 st = write( msn_file->fd, s, strlen( s ) ); 302 if( st != strlen( s ) ) 303 return msn_ftp_abort( file, "Error sending data over MSNFTP connection: %s", 304 strerror( errno ) ); 305 306 g_free( s ); 307 308 va_start(params, format); 309 s = g_strdup_vprintf(format, params); 310 va_end(params); 311 312 st = write(msn_file->fd, s, strlen(s)); 313 if (st != strlen(s)) { 314 return msn_ftp_abort(file, "Error sending data over MSNFTP connection: %s", 315 strerror(errno)); 316 } 317 318 g_free(s); 307 319 return 1; 308 320 } 309 321 310 gboolean msn_ftp_connected( gpointer data, gint fd, b_input_condition cond)322 gboolean msn_ftp_connected(gpointer data, gint fd, b_input_condition cond) 311 323 { 312 324 file_transfer_t *file = data; 313 325 msn_filetransfer_t *msn_file = file->data; 314 315 debug( "Connected to MSNFTP server, starting authentication");316 if ( !msn_ftp_write( file, "VER MSNFTP\r\n" ) )326 327 debug("Connected to MSNFTP server, starting authentication"); 328 if (!msn_ftp_write(file, "VER MSNFTP\r\n")) { 317 329 return FALSE; 318 319 sock_make_nonblocking( msn_file->fd ); 320 msn_file->r_event_id = b_input_add( msn_file->fd, B_EV_IO_READ, msn_ftp_read, file ); 321 330 } 331 332 sock_make_nonblocking(msn_file->fd); 333 msn_file->r_event_id = b_input_add(msn_file->fd, B_EV_IO_READ, msn_ftp_read, file); 334 322 335 return FALSE; 323 336 } 324 337 325 gboolean msn_ftp_handle_command( file_transfer_t *file, char* line)326 { 327 msn_filetransfer_t *msn_file = file->data; 328 char **cmd = msn_linesplit( line);338 gboolean msn_ftp_handle_command(file_transfer_t *file, char* line) 339 { 340 msn_filetransfer_t *msn_file = file->data; 341 char **cmd = msn_linesplit(line); 329 342 int count = 0; 330 if( cmd[0] ) while( cmd[++count] ); 331 332 if( count < 1 ) 333 return msn_ftp_abort( file, "Missing command in MSNFTP communication" ); 334 335 if( strcmp( cmd[0], "VER" ) == 0 ) { 336 if( strcmp( cmd[1], "MSNFTP" ) != 0 ) 337 return msn_ftp_abort( file, "Unsupported filetransfer protocol: %s", cmd[1] ); 338 if( file->sending ) 339 msn_ftp_write( file, "VER MSNFTP\r\n" ); 340 else 341 msn_ftp_write( file, "USR %s %u\r\n", msn_file->md->ic->acc->user, msn_file->auth_cookie ); 342 } else if( strcmp( cmd[0], "FIL" ) == 0 ) { 343 if( strtoul( cmd[1], NULL, 10 ) != file->file_size ) 344 return msn_ftp_abort( file, "FIL reply contains a different file size than the size in the invitation" ); 345 msn_ftp_write( file, "TFR\r\n" ); 343 344 if (cmd[0]) { 345 while (cmd[++count]) { 346 ; 347 } 348 } 349 350 if (count < 1) { 351 return msn_ftp_abort(file, "Missing command in MSNFTP communication"); 352 } 353 354 if (strcmp(cmd[0], "VER") == 0) { 355 if (strcmp(cmd[1], "MSNFTP") != 0) { 356 return msn_ftp_abort(file, "Unsupported filetransfer protocol: %s", cmd[1]); 357 } 358 if (file->sending) { 359 msn_ftp_write(file, "VER MSNFTP\r\n"); 360 } else { 361 msn_ftp_write(file, "USR %s %u\r\n", msn_file->md->ic->acc->user, msn_file->auth_cookie); 362 } 363 } else if (strcmp(cmd[0], "FIL") == 0) { 364 if (strtoul(cmd[1], NULL, 10) != file->file_size) { 365 return msn_ftp_abort(file, 366 "FIL reply contains a different file size than the size in the invitation"); 367 } 368 msn_ftp_write(file, "TFR\r\n"); 346 369 msn_file->status |= MSN_TRANSFER_RECEIVING; 347 } else if( strcmp( cmd[0], "USR" ) == 0 ) { 348 if( ( strcmp( cmd[1], msn_file->handle ) != 0 ) || 349 ( strtoul( cmd[2], NULL, 10 ) != msn_file->auth_cookie ) ) 350 msn_ftp_abort( file, "Authentication failed. " 351 "Expected handle: %s (got %s), cookie: %u (got %s)", 352 msn_file->handle, cmd[1], 353 msn_file->auth_cookie, cmd[2] ); 354 msn_ftp_write( file, "FIL %zu\r\n", file->file_size); 355 } else if( strcmp( cmd[0], "TFR" ) == 0 ) { 356 file->write_request( file ); 357 } else if( strcmp( cmd[0], "BYE" ) == 0 ) { 370 } else if (strcmp(cmd[0], "USR") == 0) { 371 if ((strcmp(cmd[1], msn_file->handle) != 0) || 372 (strtoul(cmd[2], NULL, 10) != msn_file->auth_cookie)) { 373 msn_ftp_abort(file, "Authentication failed. " 374 "Expected handle: %s (got %s), cookie: %u (got %s)", 375 msn_file->handle, cmd[1], 376 msn_file->auth_cookie, cmd[2]); 377 } 378 msn_ftp_write(file, "FIL %zu\r\n", file->file_size); 379 } else if (strcmp(cmd[0], "TFR") == 0) { 380 file->write_request(file); 381 } else if (strcmp(cmd[0], "BYE") == 0) { 358 382 unsigned int retcode = count > 1 ? atoi(cmd[1]) : 1; 359 383 360 if ( ( retcode==16777989 ) || ( retcode==16777987 ) )361 imcb_file_finished( file);362 else if( retcode==2147942405 )363 imcb_file_canceled( file, "Failure: receiver is out of disk space");364 else if( retcode==2164261682 )365 imcb_file_canceled( file, "Failure: receiver cancelled the transfer");366 else if( retcode==2164261683 )367 imcb_file_canceled( file, "Failure: sender has cancelled the transfer");368 else if( retcode==2164261694 )369 imcb_file_canceled( file, "Failure: connection is blocked");370 else {384 if ((retcode == 16777989) || (retcode == 16777987)) { 385 imcb_file_finished(file); 386 } else if (retcode == 2147942405) { 387 imcb_file_canceled(file, "Failure: receiver is out of disk space"); 388 } else if (retcode == 2164261682) { 389 imcb_file_canceled(file, "Failure: receiver cancelled the transfer"); 390 } else if (retcode == 2164261683) { 391 imcb_file_canceled(file, "Failure: sender has cancelled the transfer"); 392 } else if (retcode == 2164261694) { 393 imcb_file_canceled(file, "Failure: connection is blocked"); 394 } else { 371 395 char buf[128]; 372 396 373 sprintf( 374 imcb_file_canceled( file, buf);375 } 376 } else if ( strcmp( cmd[0], "CCL" ) == 0) {377 imcb_file_canceled( file, "Failure: receiver cancelled the transfer");378 } else { 379 msn_ftp_abort( file, "Received invalid command %s from msn client", cmd[0]);397 sprintf(buf, "Failure: unknown BYE code: %d", retcode); 398 imcb_file_canceled(file, buf); 399 } 400 } else if (strcmp(cmd[0], "CCL") == 0) { 401 imcb_file_canceled(file, "Failure: receiver cancelled the transfer"); 402 } else { 403 msn_ftp_abort(file, "Received invalid command %s from msn client", cmd[0]); 380 404 } 381 405 return TRUE; 382 406 } 383 407 384 gboolean msn_ftp_send( gpointer data, gint fd, b_input_condition cond)408 gboolean msn_ftp_send(gpointer data, gint fd, b_input_condition cond) 385 409 { 386 410 file_transfer_t *file = data; … … 389 413 msn_file->w_event_id = 0; 390 414 391 file->write_request( file);415 file->write_request(file); 392 416 393 417 return FALSE; … … 399 423 * This got a bit complicated because (at least) amsn expects packets of size 2045. 400 424 */ 401 gboolean msn_ftps_write( file_transfer_t *file, char *buffer, unsigned int len)402 { 403 msn_filetransfer_t *msn_file = file->data; 404 425 gboolean msn_ftps_write(file_transfer_t *file, char *buffer, unsigned int len) 426 { 427 msn_filetransfer_t *msn_file = file->data; 428 int ret, overflow; 405 429 406 430 /* what we can't send now */ … … 408 432 409 433 /* append what we can do the send buffer */ 410 memcpy( msn_file->sbuf + msn_file->sbufpos, buffer, MIN( len, MSNFTP_PSIZE - msn_file->sbufpos ));411 msn_file->sbufpos += MIN( len, MSNFTP_PSIZE - msn_file->sbufpos);434 memcpy(msn_file->sbuf + msn_file->sbufpos, buffer, MIN(len, MSNFTP_PSIZE - msn_file->sbufpos)); 435 msn_file->sbufpos += MIN(len, MSNFTP_PSIZE - msn_file->sbufpos); 412 436 413 437 /* if we don't have enough for a full packet and there's more wait for it */ 414 if( ( msn_file->sbufpos < MSNFTP_PSIZE ) && 415 ( msn_file->data_sent + msn_file->sbufpos - 3 < file->file_size ) ) { 416 if( !msn_file->w_event_id ) 417 msn_file->w_event_id = b_input_add( msn_file->fd, B_EV_IO_WRITE, msn_ftp_send, file ); 438 if ((msn_file->sbufpos < MSNFTP_PSIZE) && 439 (msn_file->data_sent + msn_file->sbufpos - 3 < file->file_size)) { 440 if (!msn_file->w_event_id) { 441 msn_file->w_event_id = b_input_add(msn_file->fd, B_EV_IO_WRITE, msn_ftp_send, file); 442 } 418 443 return TRUE; 419 444 } … … 422 447 423 448 msn_file->sbuf[0] = 0; 424 msn_file->sbuf[1] = ( msn_file->sbufpos - 3 ) & 0xff; 425 msn_file->sbuf[2] = ( ( msn_file->sbufpos - 3 ) >> 8 ) & 0xff; 426 427 ASSERTSOCKOP( ret = send( msn_file->fd, msn_file->sbuf, msn_file->sbufpos, 0 ), "Sending" ); 428 429 msn_file->data_sent += ret - 3; 430 431 /* TODO: this should really not be fatal */ 432 if( ret < msn_file->sbufpos ) 433 return msn_ftp_abort( file, "send() sent %d instead of %d (send buffer full!)", ret, msn_file->sbufpos ); 449 msn_file->sbuf[1] = (msn_file->sbufpos - 3) & 0xff; 450 msn_file->sbuf[2] = ((msn_file->sbufpos - 3) >> 8) & 0xff; 451 452 ASSERTSOCKOP(ret = send(msn_file->fd, msn_file->sbuf, msn_file->sbufpos, 0), "Sending"); 453 454 msn_file->data_sent += ret - 3; 455 456 /* TODO: this should really not be fatal */ 457 if (ret < msn_file->sbufpos) { 458 return msn_ftp_abort(file, "send() sent %d instead of %d (send buffer full!)", ret, msn_file->sbufpos); 459 } 434 460 435 461 msn_file->sbufpos = 3; 436 462 437 if ( overflow > 0) {438 while ( overflow > ( MSNFTP_PSIZE - 3 )) {439 if ( !msn_ftps_write( file, buffer + len - overflow, MSNFTP_PSIZE - 3 ) )463 if (overflow > 0) { 464 while (overflow > (MSNFTP_PSIZE - 3)) { 465 if (!msn_ftps_write(file, buffer + len - overflow, MSNFTP_PSIZE - 3)) { 440 466 return FALSE; 467 } 441 468 overflow -= MSNFTP_PSIZE - 3; 442 469 } 443 return msn_ftps_write( file, buffer + len - overflow, overflow);444 } 445 446 if ( msn_file->data_sent == file->file_size) {447 if ( msn_file->w_event_id) {448 b_event_remove( msn_file->w_event_id);470 return msn_ftps_write(file, buffer + len - overflow, overflow); 471 } 472 473 if (msn_file->data_sent == file->file_size) { 474 if (msn_file->w_event_id) { 475 b_event_remove(msn_file->w_event_id); 449 476 msn_file->w_event_id = 0; 450 477 } 451 478 } else { 452 479 /* we might already be listening if this is data from an overflow */ 453 if( !msn_file->w_event_id ) 454 msn_file->w_event_id = b_input_add( msn_file->fd, B_EV_IO_WRITE, msn_ftp_send, file ); 455 } 456 457 return TRUE; 480 if (!msn_file->w_event_id) { 481 msn_file->w_event_id = b_input_add(msn_file->fd, B_EV_IO_WRITE, msn_ftp_send, file); 482 } 483 } 484 485 return TRUE; 458 486 } 459 487 460 488 /* Binary part of the file transfer protocol */ 461 gboolean msn_ftpr_read( file_transfer_t *file )489 gboolean msn_ftpr_read(file_transfer_t *file) 462 490 { 463 491 msn_filetransfer_t *msn_file = file->data; … … 465 493 unsigned char buf[3]; 466 494 467 if ( msn_file->data_remaining) {495 if (msn_file->data_remaining) { 468 496 msn_file->r_event_id = 0; 469 497 470 ASSERTSOCKOP( st = read( msn_file->fd, file->buffer, MIN( sizeof( file->buffer ), msn_file->data_remaining ) ), "Receiving" ); 471 472 if( st == 0 ) 473 return msn_ftp_abort( file, "Remote end closed connection"); 498 ASSERTSOCKOP(st = read(msn_file->fd, file->buffer, MIN(sizeof(file->buffer), 499 msn_file->data_remaining)), "Receiving"); 500 501 if (st == 0) { 502 return msn_ftp_abort(file, "Remote end closed connection"); 503 } 474 504 475 505 msn_file->data_sent += st; … … 477 507 msn_file->data_remaining -= st; 478 508 479 file->write( file, file->buffer, st ); 480 481 if( msn_file->data_sent >= file->file_size ) 482 imcb_file_finished( file ); 509 file->write(file, file->buffer, st); 510 511 if (msn_file->data_sent >= file->file_size) { 512 imcb_file_finished(file); 513 } 483 514 484 515 return FALSE; 485 516 } else { 486 ASSERTSOCKOP( st = read( msn_file->fd, buf, 1 ), "Receiving");487 if ( st == 0) {488 return msn_ftp_abort( file, "read returned EOF while reading data header from msn client");489 } else if ( buf[0] == '\r' || buf[0] == '\n') {490 debug( "Discarding extraneous newline");491 } else if ( buf[0] != 0) {492 msn_ftp_abort( 517 ASSERTSOCKOP(st = read(msn_file->fd, buf, 1), "Receiving"); 518 if (st == 0) { 519 return msn_ftp_abort(file, "read returned EOF while reading data header from msn client"); 520 } else if (buf[0] == '\r' || buf[0] == '\n') { 521 debug("Discarding extraneous newline"); 522 } else if (buf[0] != 0) { 523 msn_ftp_abort(file, "Remote end canceled the transfer"); 493 524 /* don't really care about these last 2 (should be 0,0) */ 494 read( msn_file->fd, buf, 2);525 read(msn_file->fd, buf, 2); 495 526 return FALSE; 496 527 } else { 497 528 unsigned int size; 498 ASSERTSOCKOP( st = read( msn_file->fd, buf, 2 ), "Receiving" ); 499 if( st < 2 ) 500 return msn_ftp_abort( file, "read returned EOF while reading data header from msn client" ); 529 ASSERTSOCKOP(st = read(msn_file->fd, buf, 2), "Receiving"); 530 if (st < 2) { 531 return msn_ftp_abort(file, 532 "read returned EOF while reading data header from msn client"); 533 } 501 534 502 535 size = buf[0] + ((unsigned int) buf[1] << 8); … … 508 541 509 542 /* Text mode part of the file transfer protocol */ 510 gboolean msn_ftp_txtproto( file_transfer_t *file)543 gboolean msn_ftp_txtproto(file_transfer_t *file) 511 544 { 512 545 msn_filetransfer_t *msn_file = file->data; … … 514 547 char *tbuf = msn_file->tbuf; 515 548 516 ASSERTSOCKOP( st = read( msn_file->fd, 517 tbuf + msn_file->tbufpos, 518 sizeof( msn_file->tbuf ) - msn_file->tbufpos ), 519 "Receiving" ); 520 521 if( st == 0 ) 522 return msn_ftp_abort( file, "read returned EOF while reading text from msn client" ); 549 ASSERTSOCKOP(st = read(msn_file->fd, 550 tbuf + msn_file->tbufpos, 551 sizeof(msn_file->tbuf) - msn_file->tbufpos), 552 "Receiving"); 553 554 if (st == 0) { 555 return msn_ftp_abort(file, "read returned EOF while reading text from msn client"); 556 } 523 557 524 558 msn_file->tbufpos += st; 525 559 526 560 do { 527 for ( ;i < msn_file->tbufpos; i++) {528 if ( tbuf[i] == '\n' || tbuf[i] == '\r') {561 for (; i < msn_file->tbufpos; i++) { 562 if (tbuf[i] == '\n' || tbuf[i] == '\r') { 529 563 tbuf[i] = '\0'; 530 if( i > 0 ) 531 msn_ftp_handle_command( file, tbuf ); 532 else 533 while( tbuf[i] == '\n' || tbuf[i] == '\r' ) i++; 534 memmove( tbuf, tbuf + i + 1, msn_file->tbufpos - i - 1 ); 564 if (i > 0) { 565 msn_ftp_handle_command(file, tbuf); 566 } else { 567 while (tbuf[i] == '\n' || tbuf[i] == '\r') { 568 i++; 569 } 570 } 571 memmove(tbuf, tbuf + i + 1, msn_file->tbufpos - i - 1); 535 572 msn_file->tbufpos -= i + 1; 536 573 i = 0; … … 538 575 } 539 576 } 540 } while ( i < msn_file->tbufpos ); 541 542 if( msn_file->tbufpos == sizeof( msn_file->tbuf ) ) 543 return msn_ftp_abort( file, 544 "Line exceeded %d bytes in text protocol", 545 sizeof( msn_file->tbuf ) ); 577 } while (i < msn_file->tbufpos); 578 579 if (msn_file->tbufpos == sizeof(msn_file->tbuf)) { 580 return msn_ftp_abort(file, 581 "Line exceeded %d bytes in text protocol", 582 sizeof(msn_file->tbuf)); 583 } 546 584 return TRUE; 547 585 } 548 586 549 gboolean msn_ftp_read( gpointer data, gint fd, b_input_condition cond)587 gboolean msn_ftp_read(gpointer data, gint fd, b_input_condition cond) 550 588 { 551 589 file_transfer_t *file = data; 552 590 msn_filetransfer_t *msn_file = file->data; 553 554 if( msn_file->status & MSN_TRANSFER_RECEIVING ) 555 return msn_ftpr_read( file ); 556 else 557 return msn_ftp_txtproto( file ); 558 } 559 560 void msn_ftp_free( file_transfer_t *file ) 561 { 562 msn_filetransfer_t *msn_file = file->data; 563 564 if( msn_file->r_event_id ) 565 b_event_remove( msn_file->r_event_id ); 566 567 if( msn_file->w_event_id ) 568 b_event_remove( msn_file->w_event_id ); 569 570 if( msn_file->fd != -1 ) 571 closesocket( msn_file->fd ); 572 573 msn_file->md->filetransfers = g_slist_remove( msn_file->md->filetransfers, msn_file->dcc ); 574 575 g_free( msn_file->handle ); 576 577 g_free( msn_file ); 578 } 579 580 void msn_ftpr_accept( file_transfer_t *file ) 581 { 582 msn_filetransfer_t *msn_file = file->data; 583 584 msn_ftp_invitation_cmd( msn_file->md->ic, msn_file->handle, msn_file->invite_cookie, "ACCEPT", 585 "Launch-Application: FALSE\r\n" 586 "Request-Data: IP-Address:\r\n"); 587 } 588 589 void msn_ftp_finished( file_transfer_t *file ) 590 { 591 msn_ftp_write( file, "BYE 16777989\r\n" ); 592 } 593 594 void msn_ftp_canceled( file_transfer_t *file, char *reason ) 595 { 596 msn_filetransfer_t *msn_file = file->data; 597 598 msn_ftp_cancel_invite( msn_file->md->ic, msn_file->handle, 599 msn_file->invite_cookie, 600 file->status & FT_STATUS_TRANSFERRING ? 601 "FTTIMEOUT" : 602 "FAIL" ); 603 604 imcb_log( msn_file->md->ic, "File transfer aborted: %s", reason ); 605 } 606 607 gboolean msn_ftpr_write_request( file_transfer_t *file ) 608 { 609 msn_filetransfer_t *msn_file = file->data; 610 if( msn_file->r_event_id != 0 ) { 611 msn_ftp_abort( file, 612 "BUG in MSN file transfer:" 613 "write_request called when" 614 "already watching for input" ); 591 592 if (msn_file->status & MSN_TRANSFER_RECEIVING) { 593 return msn_ftpr_read(file); 594 } else { 595 return msn_ftp_txtproto(file); 596 } 597 } 598 599 void msn_ftp_free(file_transfer_t *file) 600 { 601 msn_filetransfer_t *msn_file = file->data; 602 603 if (msn_file->r_event_id) { 604 b_event_remove(msn_file->r_event_id); 605 } 606 607 if (msn_file->w_event_id) { 608 b_event_remove(msn_file->w_event_id); 609 } 610 611 if (msn_file->fd != -1) { 612 closesocket(msn_file->fd); 613 } 614 615 msn_file->md->filetransfers = g_slist_remove(msn_file->md->filetransfers, msn_file->dcc); 616 617 g_free(msn_file->handle); 618 619 g_free(msn_file); 620 } 621 622 void msn_ftpr_accept(file_transfer_t *file) 623 { 624 msn_filetransfer_t *msn_file = file->data; 625 626 msn_ftp_invitation_cmd(msn_file->md->ic, msn_file->handle, msn_file->invite_cookie, "ACCEPT", 627 "Launch-Application: FALSE\r\n" 628 "Request-Data: IP-Address:\r\n"); 629 } 630 631 void msn_ftp_finished(file_transfer_t *file) 632 { 633 msn_ftp_write(file, "BYE 16777989\r\n"); 634 } 635 636 void msn_ftp_canceled(file_transfer_t *file, char *reason) 637 { 638 msn_filetransfer_t *msn_file = file->data; 639 640 msn_ftp_cancel_invite(msn_file->md->ic, msn_file->handle, 641 msn_file->invite_cookie, 642 file->status & FT_STATUS_TRANSFERRING ? 643 "FTTIMEOUT" : 644 "FAIL"); 645 646 imcb_log(msn_file->md->ic, "File transfer aborted: %s", reason); 647 } 648 649 gboolean msn_ftpr_write_request(file_transfer_t *file) 650 { 651 msn_filetransfer_t *msn_file = file->data; 652 653 if (msn_file->r_event_id != 0) { 654 msn_ftp_abort(file, 655 "BUG in MSN file transfer:" 656 "write_request called when" 657 "already watching for input"); 615 658 return FALSE; 616 659 } 617 660 618 msn_file->r_event_id = 619 b_input_add( msn_file->fd, B_EV_IO_READ, msn_ftp_read, file);661 msn_file->r_event_id = 662 b_input_add(msn_file->fd, B_EV_IO_READ, msn_ftp_read, file); 620 663 621 664 return TRUE; -
protocols/msn/invitation.h
raf359b4 r5ebff60 12 12 the Free Software Foundation; either version 2 of the License, or 13 13 (at your option) any later version. 14 14 15 15 This program is distributed in the hope that it will be useful, 16 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 18 GNU General Public License for more details. 19 19 20 20 You should have received a copy of the GNU General Public License with 21 21 the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; … … 29 29 #include "msn.h" 30 30 31 #define MSN_INVITE_HEADERS 32 33 31 #define MSN_INVITE_HEADERS "MIME-Version: 1.0\r\n" \ 32 "Content-Type: text/x-msmsgsinvite; charset=UTF-8\r\n" \ 33 "\r\n" 34 34 35 35 #define MSNFTP_PSIZE 2048 36 36 37 37 typedef enum { 38 MSN_TRANSFER_RECEIVING 39 MSN_TRANSFER_SENDING 38 MSN_TRANSFER_RECEIVING = 1, 39 MSN_TRANSFER_SENDING = 2 40 40 } msn_filetransfer_status_t; 41 41 42 typedef struct msn_filetransfer 43 { 44 /* Generic invitation data */ 42 typedef struct msn_filetransfer { 43 /* Generic invitation data */ 45 44 /* msn_data instance this invitation was received with. */ 46 45 struct msn_data *md; … … 65 64 char tbuf[256]; 66 65 unsigned int tbufpos; 67 66 68 67 unsigned int data_sent; 69 68 70 69 gint r_event_id; 71 70 gint w_event_id; 72 71 73 72 unsigned char sbuf[2048]; 74 73 int sbufpos; … … 76 75 } msn_filetransfer_t; 77 76 78 void msn_invitation_invite( struct msn_switchboard *sb, char *handle, unsigned int cookie, char *body, int blen);79 void msn_invitation_accept( struct msn_switchboard *sb, char *handle, unsigned int cookie, char *body, int blen);80 void msn_invitation_cancel( struct msn_switchboard *sb, char *handle, unsigned int cookie, char *body, int blen);77 void msn_invitation_invite(struct msn_switchboard *sb, char *handle, unsigned int cookie, char *body, int blen); 78 void msn_invitation_accept(struct msn_switchboard *sb, char *handle, unsigned int cookie, char *body, int blen); 79 void msn_invitation_cancel(struct msn_switchboard *sb, char *handle, unsigned int cookie, char *body, int blen); 81 80 82 81 #endif -
protocols/msn/msn.c
raf359b4 r5ebff60 1 1 /********************************************************************\ 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * … … 32 32 GSList *msn_switchboards; 33 33 34 static char *set_eval_display_name( set_t *set, char *value);35 36 static void msn_init( account_t *acc)34 static char *set_eval_display_name(set_t *set, char *value); 35 36 static void msn_init(account_t *acc) 37 37 { 38 38 set_t *s; 39 40 s = set_add( &acc->set, "display_name", NULL, set_eval_display_name, acc);39 40 s = set_add(&acc->set, "display_name", NULL, set_eval_display_name, acc); 41 41 s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY; 42 43 s = set_add( &acc->set, "server", MSN_NS_HOST, set_eval_account, acc);42 43 s = set_add(&acc->set, "server", MSN_NS_HOST, set_eval_account, acc); 44 44 s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY; 45 45 46 s = set_add( &acc->set, "port", MSN_NS_PORT, set_eval_int, acc);46 s = set_add(&acc->set, "port", MSN_NS_PORT, set_eval_int, acc); 47 47 s->flags |= ACC_SET_OFFLINE_ONLY; 48 48 49 set_add( &acc->set, "mail_notifications", "false", set_eval_bool, acc);50 set_add( &acc->set, "switchboard_keepalives", "false", set_eval_bool, acc);51 49 set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc); 50 set_add(&acc->set, "switchboard_keepalives", "false", set_eval_bool, acc); 51 52 52 acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE | 53 53 ACC_FLAG_HANDLE_DOMAINS; 54 54 } 55 55 56 static void msn_login( account_t *acc)57 { 58 struct im_connection *ic = imcb_new( acc);59 struct msn_data *md = g_new0( struct msn_data, 1);60 56 static void msn_login(account_t *acc) 57 { 58 struct im_connection *ic = imcb_new(acc); 59 struct msn_data *md = g_new0(struct msn_data, 1); 60 61 61 ic->proto_data = md; 62 62 ic->flags |= OPT_PONGS | OPT_PONGED; 63 64 if( strchr( acc->user, '@' ) == NULL ) 65 { 66 imcb_error( ic, "Invalid account name" ); 67 imc_logout( ic, FALSE ); 63 64 if (strchr(acc->user, '@') == NULL) { 65 imcb_error(ic, "Invalid account name"); 66 imc_logout(ic, FALSE); 68 67 return; 69 68 } 70 69 71 70 md->ic = ic; 72 71 md->away_state = msn_away_state_list; 73 md->domaintree = g_tree_new( msn_domaintree_cmp);72 md->domaintree = g_tree_new(msn_domaintree_cmp); 74 73 md->ns->fd = -1; 75 76 msn_connections = g_slist_prepend( msn_connections, ic);77 78 imcb_log( ic, "Connecting");79 msn_ns_connect( 80 set_getstr( &ic->acc->set, "server"),81 set_getint( &ic->acc->set, "port" ));82 } 83 84 static void msn_logout( struct im_connection *ic)74 75 msn_connections = g_slist_prepend(msn_connections, ic); 76 77 imcb_log(ic, "Connecting"); 78 msn_ns_connect(ic, md->ns, 79 set_getstr(&ic->acc->set, "server"), 80 set_getint(&ic->acc->set, "port")); 81 } 82 83 static void msn_logout(struct im_connection *ic) 85 84 { 86 85 struct msn_data *md = ic->proto_data; 87 86 GSList *l; 88 87 int i; 89 90 if( md ) 91 { 88 89 if (md) { 92 90 /** Disabling MSN ft support for now. 93 91 while( md->filetransfers ) { 94 92 imcb_file_canceled( md->filetransfers->data, "Closing connection" ); 95 93 } 96 94 */ 97 98 msn_ns_close( md->ns ); 99 100 while( md->switchboards ) 101 msn_sb_destroy( md->switchboards->data ); 102 103 msn_msgq_purge( ic, &md->msgq ); 104 msn_soapq_flush( ic, FALSE ); 105 106 for( i = 0; i < sizeof( md->tokens ) / sizeof( md->tokens[0] ); i ++ ) 107 g_free( md->tokens[i] ); 108 g_free( md->lock_key ); 109 g_free( md->pp_policy ); 110 g_free( md->uuid ); 111 112 while( md->groups ) 113 { 95 96 msn_ns_close(md->ns); 97 98 while (md->switchboards) { 99 msn_sb_destroy(md->switchboards->data); 100 } 101 102 msn_msgq_purge(ic, &md->msgq); 103 msn_soapq_flush(ic, FALSE); 104 105 for (i = 0; i < sizeof(md->tokens) / sizeof(md->tokens[0]); i++) { 106 g_free(md->tokens[i]); 107 } 108 g_free(md->lock_key); 109 g_free(md->pp_policy); 110 g_free(md->uuid); 111 112 while (md->groups) { 114 113 struct msn_group *mg = md->groups->data; 115 g_free( mg->id ); 116 g_free( mg->name ); 117 g_free( mg ); 118 md->groups = g_slist_remove( md->groups, mg ); 119 } 120 121 g_free( md->profile_rid ); 122 123 if( md->domaintree ) 124 g_tree_destroy( md->domaintree ); 114 g_free(mg->id); 115 g_free(mg->name); 116 g_free(mg); 117 md->groups = g_slist_remove(md->groups, mg); 118 } 119 120 g_free(md->profile_rid); 121 122 if (md->domaintree) { 123 g_tree_destroy(md->domaintree); 124 } 125 125 md->domaintree = NULL; 126 127 while( md->grpq ) 128 { 126 127 while (md->grpq) { 129 128 struct msn_groupadd *ga = md->grpq->data; 130 g_free( ga->group ); 131 g_free( ga->who ); 132 g_free( ga ); 133 md->grpq = g_slist_remove( md->grpq, ga ); 134 } 135 136 g_free( md ); 137 } 138 139 for( l = ic->permit; l; l = l->next ) 140 g_free( l->data ); 141 g_slist_free( ic->permit ); 142 143 for( l = ic->deny; l; l = l->next ) 144 g_free( l->data ); 145 g_slist_free( ic->deny ); 146 147 msn_connections = g_slist_remove( msn_connections, ic ); 148 } 149 150 static int msn_buddy_msg( struct im_connection *ic, char *who, char *message, int away ) 151 { 152 struct bee_user *bu = bee_user_by_handle( ic->bee, ic, who ); 129 g_free(ga->group); 130 g_free(ga->who); 131 g_free(ga); 132 md->grpq = g_slist_remove(md->grpq, ga); 133 } 134 135 g_free(md); 136 } 137 138 for (l = ic->permit; l; l = l->next) { 139 g_free(l->data); 140 } 141 g_slist_free(ic->permit); 142 143 for (l = ic->deny; l; l = l->next) { 144 g_free(l->data); 145 } 146 g_slist_free(ic->deny); 147 148 msn_connections = g_slist_remove(msn_connections, ic); 149 } 150 151 static int msn_buddy_msg(struct im_connection *ic, char *who, char *message, int away) 152 { 153 struct bee_user *bu = bee_user_by_handle(ic->bee, ic, who); 153 154 struct msn_buddy_data *bd = bu ? bu->data : NULL; 154 155 struct msn_switchboard *sb; 155 156 156 157 #ifdef DEBUG 157 if( strcmp( who, "raw" ) == 0 ) 158 { 159 msn_ns_write( ic, -1, "%s\r\n", message ); 160 } 161 else 158 if (strcmp(who, "raw") == 0) { 159 msn_ns_write(ic, -1, "%s\r\n", message); 160 } else 162 161 #endif 163 if( bd && bd->flags & MSN_BUDDY_FED ) 164 { 165 msn_ns_sendmessage( ic, bu, message ); 166 } 167 else if( ( sb = msn_sb_by_handle( ic, who ) ) ) 168 { 169 return( msn_sb_sendmessage( sb, message ) ); 170 } 171 else 172 { 162 if (bd && bd->flags & MSN_BUDDY_FED) { 163 msn_ns_sendmessage(ic, bu, message); 164 } else if ((sb = msn_sb_by_handle(ic, who))) { 165 return(msn_sb_sendmessage(sb, message)); 166 } else { 173 167 struct msn_message *m; 174 168 175 169 /* Create a message. We have to arrange a usable switchboard, and send the message later. */ 176 m = g_new0( struct msn_message, 1);177 m->who = g_strdup( who);178 m->text = g_strdup( message);179 180 return msn_sb_write_msg( ic, m);181 } 182 183 return( 0);184 } 185 186 static GList *msn_away_states( struct im_connection *ic)170 m = g_new0(struct msn_message, 1); 171 m->who = g_strdup(who); 172 m->text = g_strdup(message); 173 174 return msn_sb_write_msg(ic, m); 175 } 176 177 return(0); 178 } 179 180 static GList *msn_away_states(struct im_connection *ic) 187 181 { 188 182 static GList *l = NULL; 189 183 int i; 190 191 if( l == NULL ) 192 for( i = 0; *msn_away_state_list[i].code; i ++ ) 193 if( *msn_away_state_list[i].name ) 194 l = g_list_append( l, (void*) msn_away_state_list[i].name ); 195 184 185 if (l == NULL) { 186 for (i = 0; *msn_away_state_list[i].code; i++) { 187 if (*msn_away_state_list[i].name) { 188 l = g_list_append(l, (void *) msn_away_state_list[i].name); 189 } 190 } 191 } 192 196 193 return l; 197 194 } 198 195 199 static void msn_set_away( struct im_connection *ic, char *state, char *message)196 static void msn_set_away(struct im_connection *ic, char *state, char *message) 200 197 { 201 198 char *uux; 202 199 struct msn_data *md = ic->proto_data; 203 204 if ( state == NULL )200 201 if (state == NULL) { 205 202 md->away_state = msn_away_state_list; 206 else if( ( md->away_state = msn_away_state_by_name( state ) ) == NULL )203 } else if ((md->away_state = msn_away_state_by_name(state)) == NULL) { 207 204 md->away_state = msn_away_state_list + 1; 208 209 if( !msn_ns_write( ic, -1, "CHG %d %s %d:%02d\r\n", ++md->trId, md->away_state->code, MSN_CAP1, MSN_CAP2 ) ) 205 } 206 207 if (!msn_ns_write(ic, -1, "CHG %d %s %d:%02d\r\n", ++md->trId, md->away_state->code, MSN_CAP1, MSN_CAP2)) { 210 208 return; 211 212 uux = g_markup_printf_escaped( "<EndpointData><Capabilities>%d:%02d" 213 "</Capabilities></EndpointData>", 214 MSN_CAP1, MSN_CAP2 ); 215 msn_ns_write( ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen( uux ), uux ); 216 g_free( uux ); 217 218 uux = g_markup_printf_escaped( "<PrivateEndpointData><EpName>%s</EpName>" 219 "<Idle>%s</Idle><ClientType>%d</ClientType>" 220 "<State>%s</State></PrivateEndpointData>", 221 md->uuid, 222 strcmp( md->away_state->code, "IDL" ) ? "false" : "true", 223 1, /* ? */ 224 md->away_state->code ); 225 msn_ns_write( ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen( uux ), uux ); 226 g_free( uux ); 227 228 uux = g_markup_printf_escaped( "<Data><DDP></DDP><PSM>%s</PSM>" 229 "<CurrentMedia></CurrentMedia>" 230 "<MachineGuid>%s</MachineGuid></Data>", 231 message ? message : "", md->uuid ); 232 msn_ns_write( ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen( uux ), uux ); 233 g_free( uux ); 234 } 235 236 static void msn_get_info(struct im_connection *ic, char *who) 209 } 210 211 uux = g_markup_printf_escaped("<EndpointData><Capabilities>%d:%02d" 212 "</Capabilities></EndpointData>", 213 MSN_CAP1, MSN_CAP2); 214 msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux); 215 g_free(uux); 216 217 uux = g_markup_printf_escaped("<PrivateEndpointData><EpName>%s</EpName>" 218 "<Idle>%s</Idle><ClientType>%d</ClientType>" 219 "<State>%s</State></PrivateEndpointData>", 220 md->uuid, 221 strcmp(md->away_state->code, "IDL") ? "false" : "true", 222 1, /* ? */ 223 md->away_state->code); 224 msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux); 225 g_free(uux); 226 227 uux = g_markup_printf_escaped("<Data><DDP></DDP><PSM>%s</PSM>" 228 "<CurrentMedia></CurrentMedia>" 229 "<MachineGuid>%s</MachineGuid></Data>", 230 message ? message : "", md->uuid); 231 msn_ns_write(ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen(uux), uux); 232 g_free(uux); 233 } 234 235 static void msn_get_info(struct im_connection *ic, char *who) 237 236 { 238 237 /* Just make an URL and let the user fetch the info */ 239 imcb_log( ic, "%s\n%s: %s%s", _("User Info"), _("For now, fetch yourself"), PROFILE_URL, who ); 240 } 241 242 static void msn_add_buddy( struct im_connection *ic, char *who, char *group ) 243 { 244 struct bee_user *bu = bee_user_by_handle( ic->bee, ic, who ); 245 246 msn_buddy_list_add( ic, MSN_BUDDY_FL, who, who, group ); 247 if( bu && bu->group ) 248 msn_buddy_list_remove( ic, MSN_BUDDY_FL, who, bu->group->name ); 249 } 250 251 static void msn_remove_buddy( struct im_connection *ic, char *who, char *group ) 252 { 253 msn_buddy_list_remove( ic, MSN_BUDDY_FL, who, NULL ); 254 } 255 256 static void msn_chat_msg( struct groupchat *c, char *message, int flags ) 257 { 258 struct msn_switchboard *sb = msn_sb_by_chat( c ); 259 260 if( sb ) 261 msn_sb_sendmessage( sb, message ); 238 imcb_log(ic, "%s\n%s: %s%s", _("User Info"), _("For now, fetch yourself"), PROFILE_URL, who); 239 } 240 241 static void msn_add_buddy(struct im_connection *ic, char *who, char *group) 242 { 243 struct bee_user *bu = bee_user_by_handle(ic->bee, ic, who); 244 245 msn_buddy_list_add(ic, MSN_BUDDY_FL, who, who, group); 246 if (bu && bu->group) { 247 msn_buddy_list_remove(ic, MSN_BUDDY_FL, who, bu->group->name); 248 } 249 } 250 251 static void msn_remove_buddy(struct im_connection *ic, char *who, char *group) 252 { 253 msn_buddy_list_remove(ic, MSN_BUDDY_FL, who, NULL); 254 } 255 256 static void msn_chat_msg(struct groupchat *c, char *message, int flags) 257 { 258 struct msn_switchboard *sb = msn_sb_by_chat(c); 259 260 if (sb) { 261 msn_sb_sendmessage(sb, message); 262 } 262 263 /* FIXME: Error handling (although this can't happen unless something's 263 264 already severely broken) disappeared here! */ 264 265 } 265 266 266 static void msn_chat_invite( struct groupchat *c, char *who, char *message ) 267 { 268 struct msn_switchboard *sb = msn_sb_by_chat( c ); 269 270 if( sb ) 271 msn_sb_write( sb, "CAL %d %s\r\n", ++sb->trId, who ); 272 } 273 274 static void msn_chat_leave( struct groupchat *c ) 275 { 276 struct msn_switchboard *sb = msn_sb_by_chat( c ); 277 278 if( sb ) 279 msn_sb_write( sb, "OUT\r\n" ); 280 } 281 282 static struct groupchat *msn_chat_with( struct im_connection *ic, char *who ) 267 static void msn_chat_invite(struct groupchat *c, char *who, char *message) 268 { 269 struct msn_switchboard *sb = msn_sb_by_chat(c); 270 271 if (sb) { 272 msn_sb_write(sb, "CAL %d %s\r\n", ++sb->trId, who); 273 } 274 } 275 276 static void msn_chat_leave(struct groupchat *c) 277 { 278 struct msn_switchboard *sb = msn_sb_by_chat(c); 279 280 if (sb) { 281 msn_sb_write(sb, "OUT\r\n"); 282 } 283 } 284 285 static struct groupchat *msn_chat_with(struct im_connection *ic, char *who) 283 286 { 284 287 struct msn_switchboard *sb; 285 struct groupchat *c = imcb_chat_new( ic, who ); 286 287 if( ( sb = msn_sb_by_handle( ic, who ) ) ) 288 { 289 debug( "Converting existing switchboard to %s to a groupchat", who ); 290 return msn_sb_to_chat( sb ); 291 } 292 else 293 { 288 struct groupchat *c = imcb_chat_new(ic, who); 289 290 if ((sb = msn_sb_by_handle(ic, who))) { 291 debug("Converting existing switchboard to %s to a groupchat", who); 292 return msn_sb_to_chat(sb); 293 } else { 294 294 struct msn_message *m; 295 295 296 296 /* Create a magic message. This is quite hackish, but who cares? :-P */ 297 m = g_new0( struct msn_message, 1);298 m->who = g_strdup( who);299 m->text = g_strdup( GROUPCHAT_SWITCHBOARD_MESSAGE);300 301 msn_sb_write_msg( ic, m);297 m = g_new0(struct msn_message, 1); 298 m->who = g_strdup(who); 299 m->text = g_strdup(GROUPCHAT_SWITCHBOARD_MESSAGE); 300 301 msn_sb_write_msg(ic, m); 302 302 303 303 return c; … … 305 305 } 306 306 307 static void msn_keepalive( struct im_connection *ic)308 { 309 msn_ns_write( ic, -1, "PNG\r\n");310 } 311 312 static void msn_add_permit( struct im_connection *ic, char *who)313 { 314 msn_buddy_list_add( ic, MSN_BUDDY_AL, who, who, NULL);315 } 316 317 static void msn_rem_permit( struct im_connection *ic, char *who)318 { 319 msn_buddy_list_remove( ic, MSN_BUDDY_AL, who, NULL);320 } 321 322 static void msn_add_deny( struct im_connection *ic, char *who)307 static void msn_keepalive(struct im_connection *ic) 308 { 309 msn_ns_write(ic, -1, "PNG\r\n"); 310 } 311 312 static void msn_add_permit(struct im_connection *ic, char *who) 313 { 314 msn_buddy_list_add(ic, MSN_BUDDY_AL, who, who, NULL); 315 } 316 317 static void msn_rem_permit(struct im_connection *ic, char *who) 318 { 319 msn_buddy_list_remove(ic, MSN_BUDDY_AL, who, NULL); 320 } 321 322 static void msn_add_deny(struct im_connection *ic, char *who) 323 323 { 324 324 struct msn_switchboard *sb; 325 326 msn_buddy_list_add( ic, MSN_BUDDY_BL, who, who, NULL);327 325 326 msn_buddy_list_add(ic, MSN_BUDDY_BL, who, who, NULL); 327 328 328 /* If there's still a conversation with this person, close it. */ 329 if( ( sb = msn_sb_by_handle( ic, who ) ) ) 330 { 331 msn_sb_destroy( sb ); 332 } 333 } 334 335 static void msn_rem_deny( struct im_connection *ic, char *who ) 336 { 337 msn_buddy_list_remove( ic, MSN_BUDDY_BL, who, NULL ); 338 } 339 340 static int msn_send_typing( struct im_connection *ic, char *who, int typing ) 341 { 342 struct bee_user *bu = bee_user_by_handle( ic->bee, ic, who ); 343 344 if( !( bu->flags & BEE_USER_ONLINE ) ) 329 if ((sb = msn_sb_by_handle(ic, who))) { 330 msn_sb_destroy(sb); 331 } 332 } 333 334 static void msn_rem_deny(struct im_connection *ic, char *who) 335 { 336 msn_buddy_list_remove(ic, MSN_BUDDY_BL, who, NULL); 337 } 338 339 static int msn_send_typing(struct im_connection *ic, char *who, int typing) 340 { 341 struct bee_user *bu = bee_user_by_handle(ic->bee, ic, who); 342 343 if (!(bu->flags & BEE_USER_ONLINE)) { 345 344 return 0; 346 else if( typing & OPT_TYPING )347 return( msn_buddy_msg( ic, who, TYPING_NOTIFICATION_MESSAGE, 0 ));348 else345 } else if (typing & OPT_TYPING) { 346 return(msn_buddy_msg(ic, who, TYPING_NOTIFICATION_MESSAGE, 0)); 347 } else { 349 348 return 1; 350 } 351 352 static char *set_eval_display_name( set_t *set, char *value ) 349 } 350 } 351 352 static char *set_eval_display_name(set_t *set, char *value) 353 353 { 354 354 account_t *acc = set->data; 355 355 struct im_connection *ic = acc->ic; 356 356 struct msn_data *md = ic->proto_data; 357 358 if( md->flags & MSN_EMAIL_UNVERIFIED ) 359 imcb_log( ic, "Warning: Your e-mail address is unverified. MSN doesn't allow " 360 "changing your display name until your e-mail address is verified." ); 361 362 if( md->flags & MSN_GOT_PROFILE_DN ) 363 msn_soap_profile_set_dn( ic, value ); 364 else 365 msn_soap_addressbook_set_display_name( ic, value ); 366 367 return msn_ns_set_display_name( ic, value ) ? value : NULL; 368 } 369 370 static void msn_buddy_data_add( bee_user_t *bu ) 357 358 if (md->flags & MSN_EMAIL_UNVERIFIED) { 359 imcb_log(ic, "Warning: Your e-mail address is unverified. MSN doesn't allow " 360 "changing your display name until your e-mail address is verified."); 361 } 362 363 if (md->flags & MSN_GOT_PROFILE_DN) { 364 msn_soap_profile_set_dn(ic, value); 365 } else { 366 msn_soap_addressbook_set_display_name(ic, value); 367 } 368 369 return msn_ns_set_display_name(ic, value) ? value : NULL; 370 } 371 372 static void msn_buddy_data_add(bee_user_t *bu) 371 373 { 372 374 struct msn_data *md = bu->ic->proto_data; 373 375 struct msn_buddy_data *bd; 374 376 char *handle; 375 376 bd = bu->data = g_new0( struct msn_buddy_data, 1 ); 377 g_tree_insert( md->domaintree, bu->handle, bu ); 378 379 for( handle = bu->handle; g_ascii_isdigit( *handle ); handle ++ ); 380 if( *handle == ':' ) 381 { 377 378 bd = bu->data = g_new0(struct msn_buddy_data, 1); 379 g_tree_insert(md->domaintree, bu->handle, bu); 380 381 for (handle = bu->handle; g_ascii_isdigit(*handle); handle++) { 382 ; 383 } 384 if (*handle == ':') { 382 385 /* Pass a nick hint so hopefully the stupid numeric prefix 383 386 won't show up to the user. */ 384 char *s = strchr( ++handle, '@' ); 385 if( s ) 386 { 387 handle = g_strndup( handle, s - handle ); 388 imcb_buddy_nick_hint( bu->ic, bu->handle, handle ); 389 g_free( handle ); 390 } 391 387 char *s = strchr(++handle, '@'); 388 if (s) { 389 handle = g_strndup(handle, s - handle); 390 imcb_buddy_nick_hint(bu->ic, bu->handle, handle); 391 g_free(handle); 392 } 393 392 394 bd->flags |= MSN_BUDDY_FED; 393 395 } 394 396 } 395 397 396 static void msn_buddy_data_free( bee_user_t *bu)398 static void msn_buddy_data_free(bee_user_t *bu) 397 399 { 398 400 struct msn_data *md = bu->ic->proto_data; 399 401 struct msn_buddy_data *bd = bu->data; 400 401 g_free( bd->cid);402 g_free( bd);403 404 g_tree_remove( md->domaintree, bu->handle);405 } 406 407 GList *msn_buddy_action_list( bee_user_t *bu)402 403 g_free(bd->cid); 404 g_free(bd); 405 406 g_tree_remove(md->domaintree, bu->handle); 407 } 408 409 GList *msn_buddy_action_list(bee_user_t *bu) 408 410 { 409 411 static GList *ret = NULL; 410 411 if( ret == NULL ) 412 { 412 413 if (ret == NULL) { 413 414 static const struct buddy_action ba[2] = { 414 415 { "NUDGE", "Draw attention" }, 415 416 }; 416 417 ret = g_list_prepend( ret, (void*) ba + 0);418 } 419 417 418 ret = g_list_prepend(ret, (void *) ba + 0); 419 } 420 420 421 return ret; 421 422 } 422 423 423 void *msn_buddy_action( struct bee_user *bu, const char *action, char * const args[], void *data ) 424 { 425 if( g_strcasecmp( action, "NUDGE" ) == 0 ) 426 msn_buddy_msg( bu->ic, bu->handle, NUDGE_MESSAGE, 0 ); 427 424 void *msn_buddy_action(struct bee_user *bu, const char *action, char * const args[], void *data) 425 { 426 if (g_strcasecmp(action, "NUDGE") == 0) { 427 msn_buddy_msg(bu->ic, bu->handle, NUDGE_MESSAGE, 0); 428 } 429 428 430 return NULL; 429 431 } … … 432 434 { 433 435 struct prpl *ret = g_new0(struct prpl, 1); 434 436 435 437 ret->name = "msn"; 436 438 ret->mms = 1409; /* this guess taken from libotr UPGRADING file */ … … 459 461 ret->buddy_action_list = msn_buddy_action_list; 460 462 ret->buddy_action = msn_buddy_action; 461 463 462 464 //ret->transfer_request = msn_ftp_transfer_request; 463 465 -
protocols/msn/msn.h
raf359b4 r5ebff60 1 1 /********************************************************************\ 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * … … 35 35 36 36 #ifdef DEBUG_MSN 37 #define debug( text... ) imcb_log( ic, text);37 #define debug(text ...) imcb_log(ic, text); 38 38 #else 39 #define debug( text...)39 #define debug(text ...) 40 40 #endif 41 41 … … 69 69 70 70 #define MSN_MESSAGE_HEADERS "MIME-Version: 1.0\r\n" \ 71 72 73 74 71 "Content-Type: text/plain; charset=UTF-8\r\n" \ 72 "User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \ 73 "X-MMS-IM-Format: FN=MS%20Shell%20Dlg; EF=; CO=0; CS=0; PF=0\r\n" \ 74 "\r\n" 75 75 76 76 #define MSN_TYPING_HEADERS "MIME-Version: 1.0\r\n" \ 77 78 79 77 "Content-Type: text/x-msmsgscontrol\r\n" \ 78 "TypingUser: %s\r\n" \ 79 "\r\n\r\n" 80 80 81 81 #define MSN_NUDGE_HEADERS "MIME-Version: 1.0\r\n" \ 82 83 84 85 82 "Content-Type: text/x-msnmsgr-datacast\r\n" \ 83 "\r\n" \ 84 "ID: 1\r\n" \ 85 "\r\n" 86 86 87 87 #define MSN_SB_KEEPALIVE_HEADERS "MIME-Version: 1.0\r\n" \ 88 89 88 "Content-Type: text/x-ping\r\n" \ 89 "\r\n\r\n" 90 90 91 91 #define PROFILE_URL "http://members.msn.com/" 92 92 93 typedef enum 94 { 93 typedef enum { 95 94 MSN_GOT_PROFILE = 1, 96 95 MSN_GOT_PROFILE_DN = 2, … … 100 99 } msn_flags_t; 101 100 102 struct msn_handler_data 103 { 101 struct msn_handler_data { 104 102 int fd, inpa; 105 103 int rxlen; 106 104 char *rxq; 107 105 108 106 int msglen; 109 107 char *cmd_text; 110 108 111 109 /* Either ic or sb */ 112 110 gpointer data; 113 114 int (*exec_command) ( struct msn_handler_data *handler, char **cmd, int count ); 115 int (*exec_message) ( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int count ); 116 }; 117 118 struct msn_data 119 { 111 112 int (*exec_command) (struct msn_handler_data *handler, char **cmd, int count); 113 int (*exec_message) (struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int count); 114 }; 115 116 struct msn_data { 120 117 struct im_connection *ic; 121 118 122 119 struct msn_handler_data ns[1]; 123 120 msn_flags_t flags; 124 121 125 122 int trId; 126 123 char *tokens[4]; 127 124 char *lock_key, *pp_policy; 128 125 char *uuid; 129 126 130 127 GSList *msgq, *grpq, *soapq; 131 128 GSList *switchboards; 132 129 int sb_failures; 133 130 time_t first_sb_failure; 134 131 135 132 const struct msn_away_state *away_state; 136 133 GSList *groups; 137 134 char *profile_rid; 138 135 139 136 /* Mostly used for sending the ADL command; since MSNP13 the client 140 137 is responsible for downloading the contact list and then sending … … 144 141 }; 145 142 146 struct msn_switchboard 147 { 143 struct msn_switchboard { 148 144 struct im_connection *ic; 149 145 150 146 /* The following two are also in the handler. TODO: Clean up. */ 151 147 int fd; … … 153 149 struct msn_handler_data *handler; 154 150 gint keepalive; 155 151 156 152 int trId; 157 153 int ready; 158 154 159 155 int session; 160 156 char *key; 161 157 162 158 GSList *msgq; 163 159 char *who; … … 165 161 }; 166 162 167 struct msn_away_state 168 { 163 struct msn_away_state { 169 164 char code[4]; 170 165 char name[16]; 171 166 }; 172 167 173 struct msn_status_code 174 { 168 struct msn_status_code { 175 169 int number; 176 170 char *text; … … 178 172 }; 179 173 180 struct msn_message 181 { 174 struct msn_message { 182 175 char *who; 183 176 char *text; 184 177 }; 185 178 186 struct msn_groupadd 187 { 179 struct msn_groupadd { 188 180 char *who; 189 181 char *group; 190 182 }; 191 183 192 typedef enum 193 { 184 typedef enum { 194 185 MSN_BUDDY_FL = 1, /* Warning: FL,AL,BL *must* be 1,2,4. */ 195 186 MSN_BUDDY_AL = 2, … … 201 192 } msn_buddy_flags_t; 202 193 203 struct msn_buddy_data 204 { 194 struct msn_buddy_data { 205 195 char *cid; 206 196 msn_buddy_flags_t flags; 207 197 }; 208 198 209 struct msn_group 210 { 199 struct msn_group { 211 200 char *name; 212 201 char *id; … … 216 205 #define STATUS_FATAL 1 217 206 #define STATUS_SB_FATAL 2 218 #define STATUS_SB_IM_SPARE 4/* Make one-to-one conversation switchboard available again, invite failed. */219 #define STATUS_SB_CHAT_SPARE 8/* Same, but also for groupchats (not used yet). */207 #define STATUS_SB_IM_SPARE 4 /* Make one-to-one conversation switchboard available again, invite failed. */ 208 #define STATUS_SB_CHAT_SPARE 8 /* Same, but also for groupchats (not used yet). */ 220 209 221 210 extern int msn_chat_id; … … 232 221 233 222 /* ns.c */ 234 int msn_ns_write( struct im_connection *ic, int fd, const char *fmt, ... ) G_GNUC_PRINTF( 3, 4);235 gboolean msn_ns_connect( struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port);236 void msn_ns_close( struct msn_handler_data *handler);237 void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error);238 void msn_auth_got_contact_list( struct im_connection *ic);239 int msn_ns_finish_login( struct im_connection *ic);240 int msn_ns_sendmessage( struct im_connection *ic, struct bee_user *bu, const char *text);241 void msn_ns_oim_send_queue( struct im_connection *ic, GSList **msgq);223 int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...) G_GNUC_PRINTF(3, 4); 224 gboolean msn_ns_connect(struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port); 225 void msn_ns_close(struct msn_handler_data *handler); 226 void msn_auth_got_passport_token(struct im_connection *ic, const char *token, const char *error); 227 void msn_auth_got_contact_list(struct im_connection *ic); 228 int msn_ns_finish_login(struct im_connection *ic); 229 int msn_ns_sendmessage(struct im_connection *ic, struct bee_user *bu, const char *text); 230 void msn_ns_oim_send_queue(struct im_connection *ic, GSList **msgq); 242 231 243 232 /* msn_util.c */ 244 int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname_, const char *group ); 245 int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group ); 246 void msn_buddy_ask( bee_user_t *bu ); 247 char **msn_linesplit( char *line ); 248 int msn_handler( struct msn_handler_data *h ); 249 void msn_msgq_purge( struct im_connection *ic, GSList **list ); 250 char *msn_p11_challenge( char *challenge ); 251 gint msn_domaintree_cmp( gconstpointer a_, gconstpointer b_ ); 252 struct msn_group *msn_group_by_name( struct im_connection *ic, const char *name ); 253 struct msn_group *msn_group_by_id( struct im_connection *ic, const char *id ); 254 int msn_ns_set_display_name( struct im_connection *ic, const char *value ); 255 const char *msn_normalize_handle( const char *handle ); 233 int msn_buddy_list_add(struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname_, 234 const char *group); 235 int msn_buddy_list_remove(struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group); 236 void msn_buddy_ask(bee_user_t *bu); 237 char **msn_linesplit(char *line); 238 int msn_handler(struct msn_handler_data *h); 239 void msn_msgq_purge(struct im_connection *ic, GSList **list); 240 char *msn_p11_challenge(char *challenge); 241 gint msn_domaintree_cmp(gconstpointer a_, gconstpointer b_); 242 struct msn_group *msn_group_by_name(struct im_connection *ic, const char *name); 243 struct msn_group *msn_group_by_id(struct im_connection *ic, const char *id); 244 int msn_ns_set_display_name(struct im_connection *ic, const char *value); 245 const char *msn_normalize_handle(const char *handle); 256 246 257 247 /* tables.c */ 258 const struct msn_away_state *msn_away_state_by_number( int number);259 const struct msn_away_state *msn_away_state_by_code( char *code);260 const struct msn_away_state *msn_away_state_by_name( char *name);261 const struct msn_status_code *msn_status_by_number( int number);248 const struct msn_away_state *msn_away_state_by_number(int number); 249 const struct msn_away_state *msn_away_state_by_code(char *code); 250 const struct msn_away_state *msn_away_state_by_name(char *name); 251 const struct msn_status_code *msn_status_by_number(int number); 262 252 263 253 /* sb.c */ 264 int msn_sb_write( struct msn_switchboard *sb, const char *fmt, ... ) G_GNUC_PRINTF( 2, 3);;265 struct msn_switchboard *msn_sb_create( struct im_connection *ic, char *host, int port, char *key, int session);266 struct msn_switchboard *msn_sb_by_handle( struct im_connection *ic, const char *handle);267 struct msn_switchboard *msn_sb_by_chat( struct groupchat *c);268 struct msn_switchboard *msn_sb_spare( struct im_connection *ic);269 int msn_sb_sendmessage( struct msn_switchboard *sb, char *text);270 struct groupchat *msn_sb_to_chat( struct msn_switchboard *sb);271 void msn_sb_destroy( struct msn_switchboard *sb);272 gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond);273 int msn_sb_write_msg( struct im_connection *ic, struct msn_message *m);274 void msn_sb_start_keepalives( struct msn_switchboard *sb, gboolean initial);275 void msn_sb_stop_keepalives( struct msn_switchboard *sb);254 int msn_sb_write(struct msn_switchboard *sb, const char *fmt, ...) G_GNUC_PRINTF(2, 3);; 255 struct msn_switchboard *msn_sb_create(struct im_connection *ic, char *host, int port, char *key, int session); 256 struct msn_switchboard *msn_sb_by_handle(struct im_connection *ic, const char *handle); 257 struct msn_switchboard *msn_sb_by_chat(struct groupchat *c); 258 struct msn_switchboard *msn_sb_spare(struct im_connection *ic); 259 int msn_sb_sendmessage(struct msn_switchboard *sb, char *text); 260 struct groupchat *msn_sb_to_chat(struct msn_switchboard *sb); 261 void msn_sb_destroy(struct msn_switchboard *sb); 262 gboolean msn_sb_connected(gpointer data, gint source, b_input_condition cond); 263 int msn_sb_write_msg(struct im_connection *ic, struct msn_message *m); 264 void msn_sb_start_keepalives(struct msn_switchboard *sb, gboolean initial); 265 void msn_sb_stop_keepalives(struct msn_switchboard *sb); 276 266 277 267 #endif //_MSN_H -
protocols/msn/msn_util.c
raf359b4 r5ebff60 1 1 /********************************************************************\ 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * … … 30 30 #include <ctype.h> 31 31 32 static char *adlrml_entry( const char *handle_, msn_buddy_flags_t list)33 { 34 char *domain, handle[strlen(handle_) +1];35 36 strcpy( handle, handle_);37 if ( ( domain = strchr( handle, '@' ) ) )32 static char *adlrml_entry(const char *handle_, msn_buddy_flags_t list) 33 { 34 char *domain, handle[strlen(handle_) + 1]; 35 36 strcpy(handle, handle_); 37 if ((domain = strchr(handle, '@'))) { 38 38 *(domain++) = '\0'; 39 else39 } else { 40 40 return NULL; 41 42 return g_markup_printf_escaped( "<ml><d n=\"%s\"><c n=\"%s\" l=\"%d\" t=\"1\"/></d></ml>", 43 domain, handle, list ); 44 } 45 46 int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname, const char *group ) 41 } 42 43 return g_markup_printf_escaped("<ml><d n=\"%s\"><c n=\"%s\" l=\"%d\" t=\"1\"/></d></ml>", 44 domain, handle, list); 45 } 46 47 int msn_buddy_list_add(struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname, 48 const char *group) 47 49 { 48 50 struct msn_data *md = ic->proto_data; … … 51 53 struct msn_buddy_data *bd; 52 54 char *adl; 53 55 54 56 *groupid = '\0'; 55 57 #if 0 56 if( group ) 57 { 58 if (group) { 58 59 int i; 59 for( i = 0; i < md->groupcount; i ++ ) 60 if( g_strcasecmp( md->grouplist[i], group ) == 0 ) 61 { 62 g_snprintf( groupid, sizeof( groupid ), " %d", i ); 60 for (i = 0; i < md->groupcount; i++) { 61 if (g_strcasecmp(md->grouplist[i], group) == 0) { 62 g_snprintf(groupid, sizeof(groupid), " %d", i); 63 63 break; 64 64 } 65 66 if( *groupid == '\0' ) 67 {65 } 66 67 if (*groupid == '\0') { 68 68 /* Have to create this group, it doesn't exist yet. */ 69 69 struct msn_groupadd *ga; 70 70 GSList *l; 71 72 for( l = md->grpq; l; l = l->next ) 73 { 71 72 for (l = md->grpq; l; l = l->next) { 74 73 ga = l->data; 75 if ( g_strcasecmp( ga->group, group ) == 0 )74 if (g_strcasecmp(ga->group, group) == 0) { 76 75 break; 77 } 78 79 ga = g_new0( struct msn_groupadd, 1 ); 80 ga->who = g_strdup( who ); 81 ga->group = g_strdup( group ); 82 md->grpq = g_slist_prepend( md->grpq, ga ); 83 84 if( l == NULL ) 85 { 86 char groupname[strlen(group)+1]; 87 strcpy( groupname, group ); 88 http_encode( groupname ); 89 g_snprintf( buf, sizeof( buf ), "ADG %d %s %d\r\n", ++md->trId, groupname, 0 ); 90 return msn_write( ic, buf, strlen( buf ) ); 91 } 92 else 93 { 76 } 77 } 78 79 ga = g_new0(struct msn_groupadd, 1); 80 ga->who = g_strdup(who); 81 ga->group = g_strdup(group); 82 md->grpq = g_slist_prepend(md->grpq, ga); 83 84 if (l == NULL) { 85 char groupname[strlen(group) + 1]; 86 strcpy(groupname, group); 87 http_encode(groupname); 88 g_snprintf(buf, sizeof(buf), "ADG %d %s %d\r\n", ++md->trId, groupname, 0); 89 return msn_write(ic, buf, strlen(buf)); 90 } else { 94 91 /* This can happen if the user's doing lots of adds to a 95 92 new group at once; we're still waiting for the server … … 100 97 } 101 98 #endif 102 103 if ( !( ( bu = bee_user_by_handle( ic->bee, ic, who )) ||104 ( bu = bee_user_new( ic->bee, ic, who, 0 ) )) ||105 !( bd = bu->data ) || bd->flags & list )99 100 if (!((bu = bee_user_by_handle(ic->bee, ic, who)) || 101 (bu = bee_user_new(ic->bee, ic, who, 0))) || 102 !(bd = bu->data) || bd->flags & list) { 106 103 return 1; 107 104 } 105 108 106 bd->flags |= list; 109 110 if ( list == MSN_BUDDY_FL )111 msn_soap_ab_contact_add( ic, bu);112 else113 msn_soap_memlist_edit( ic, who, TRUE, list);114 115 if( ( adl = adlrml_entry( who, list ) ) ) 116 {117 int st = msn_ns_write( 118 ++md->trId, strlen( adl ), adl);119 g_free( adl);120 107 108 if (list == MSN_BUDDY_FL) { 109 msn_soap_ab_contact_add(ic, bu); 110 } else { 111 msn_soap_memlist_edit(ic, who, TRUE, list); 112 } 113 114 if ((adl = adlrml_entry(who, list))) { 115 int st = msn_ns_write(ic, -1, "ADL %d %zd\r\n%s", 116 ++md->trId, strlen(adl), adl); 117 g_free(adl); 118 121 119 return st; 122 120 } 123 121 124 122 return 1; 125 123 } 126 124 127 int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group)125 int msn_buddy_list_remove(struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group) 128 126 { 129 127 struct msn_data *md = ic->proto_data; … … 132 130 struct msn_buddy_data *bd; 133 131 char *adl; 134 132 135 133 *groupid = '\0'; 136 134 #if 0 137 if( group ) 138 { 135 if (group) { 139 136 int i; 140 for( i = 0; i < md->groupcount; i ++ ) 141 if( g_strcasecmp( md->grouplist[i], group ) == 0 ) 142 { 143 g_snprintf( groupid, sizeof( groupid ), " %d", i ); 137 for (i = 0; i < md->groupcount; i++) { 138 if (g_strcasecmp(md->grouplist[i], group) == 0) { 139 g_snprintf(groupid, sizeof(groupid), " %d", i); 144 140 break; 145 141 } 142 } 146 143 } 147 144 #endif 148 149 if ( !( bu = bee_user_by_handle( ic->bee, ic, who )) ||150 !( bd = bu->data ) || !( bd->flags & list ) )145 146 if (!(bu = bee_user_by_handle(ic->bee, ic, who)) || 147 !(bd = bu->data) || !(bd->flags & list)) { 151 148 return 1; 152 149 } 150 153 151 bd->flags &= ~list; 154 155 if ( list == MSN_BUDDY_FL )156 msn_soap_ab_contact_del( ic, bu);157 else158 msn_soap_memlist_edit( ic, who, FALSE, list);159 160 if( ( adl = adlrml_entry( who, list ) ) ) 161 {162 int st = msn_ns_write( 163 ++md->trId, strlen( adl ), adl);164 g_free( adl);165 152 153 if (list == MSN_BUDDY_FL) { 154 msn_soap_ab_contact_del(ic, bu); 155 } else { 156 msn_soap_memlist_edit(ic, who, FALSE, list); 157 } 158 159 if ((adl = adlrml_entry(who, list))) { 160 int st = msn_ns_write(ic, -1, "RML %d %zd\r\n%s", 161 ++md->trId, strlen(adl), adl); 162 g_free(adl); 163 166 164 return st; 167 165 } 168 166 169 167 return 1; 170 168 } 171 169 172 struct msn_buddy_ask_data 173 { 170 struct msn_buddy_ask_data { 174 171 struct im_connection *ic; 175 172 char *handle; … … 177 174 }; 178 175 179 static void msn_buddy_ask_yes( void *data)176 static void msn_buddy_ask_yes(void *data) 180 177 { 181 178 struct msn_buddy_ask_data *bla = data; 182 183 msn_buddy_list_add( bla->ic, MSN_BUDDY_AL, bla->handle, bla->realname, NULL);184 185 imcb_ask_add( bla->ic, bla->handle, NULL);186 187 g_free( bla->handle);188 g_free( bla->realname);189 g_free( bla);190 } 191 192 static void msn_buddy_ask_no( void *data)179 180 msn_buddy_list_add(bla->ic, MSN_BUDDY_AL, bla->handle, bla->realname, NULL); 181 182 imcb_ask_add(bla->ic, bla->handle, NULL); 183 184 g_free(bla->handle); 185 g_free(bla->realname); 186 g_free(bla); 187 } 188 189 static void msn_buddy_ask_no(void *data) 193 190 { 194 191 struct msn_buddy_ask_data *bla = data; 195 196 msn_buddy_list_add( bla->ic, MSN_BUDDY_BL, bla->handle, bla->realname, NULL);197 198 g_free( bla->handle);199 g_free( bla->realname);200 g_free( bla);201 } 202 203 void msn_buddy_ask( bee_user_t *bu)192 193 msn_buddy_list_add(bla->ic, MSN_BUDDY_BL, bla->handle, bla->realname, NULL); 194 195 g_free(bla->handle); 196 g_free(bla->realname); 197 g_free(bla); 198 } 199 200 void msn_buddy_ask(bee_user_t *bu) 204 201 { 205 202 struct msn_buddy_ask_data *bla; 206 203 struct msn_buddy_data *bd = bu->data; 207 204 char buf[1024]; 208 209 if ( !( bd->flags & MSN_BUDDY_PL ) )205 206 if (!(bd->flags & MSN_BUDDY_PL)) { 210 207 return; 211 212 bla = g_new0( struct msn_buddy_ask_data, 1 ); 208 } 209 210 bla = g_new0(struct msn_buddy_ask_data, 1); 213 211 bla->ic = bu->ic; 214 bla->handle = g_strdup( bu->handle);215 bla->realname = g_strdup( bu->fullname);216 217 g_snprintf( buf, sizeof( buf),218 219 bu->handle, bu->fullname);220 imcb_ask( bu->ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no);212 bla->handle = g_strdup(bu->handle); 213 bla->realname = g_strdup(bu->fullname); 214 215 g_snprintf(buf, sizeof(buf), 216 "The user %s (%s) wants to add you to his/her buddy list.", 217 bu->handle, bu->fullname); 218 imcb_ask(bu->ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no); 221 219 } 222 220 223 221 /* *NOT* thread-safe, but that's not a problem for now... */ 224 char **msn_linesplit( char *line)222 char **msn_linesplit(char *line) 225 223 { 226 224 static char **ret = NULL; 227 225 static int size = 3; 228 226 int i, n = 0; 229 230 if( ret == NULL ) 231 ret = g_new0( char*, size ); 232 233 for( i = 0; line[i] && line[i] == ' '; i ++ ); 234 if( line[i] ) 235 { 227 228 if (ret == NULL) { 229 ret = g_new0(char*, size); 230 } 231 232 for (i = 0; line[i] && line[i] == ' '; i++) { 233 ; 234 } 235 if (line[i]) { 236 236 ret[n++] = line + i; 237 for( i ++; line[i]; i ++ ) 238 { 239 if( line[i] == ' ' ) 237 for (i++; line[i]; i++) { 238 if (line[i] == ' ') { 240 239 line[i] = 0; 241 else if( line[i] != ' ' && !line[i-1] )240 } else if (line[i] != ' ' && !line[i - 1]) { 242 241 ret[n++] = line + i; 243 244 if( n >= size ) 245 ret = g_renew( char*, ret, size += 2 ); 242 } 243 244 if (n >= size) { 245 ret = g_renew(char*, ret, size += 2); 246 } 246 247 } 247 248 } 248 249 ret[n] = NULL; 249 250 return( ret);250 251 return(ret); 251 252 } 252 253 … … 259 260 1: OK */ 260 261 261 int msn_handler( struct msn_handler_data *h)262 int msn_handler(struct msn_handler_data *h) 262 263 { 263 264 int st; 264 265 h->rxq = g_renew( char, h->rxq, h->rxlen + 1024);266 st = read( h->fd, h->rxq + h->rxlen, 1024);265 266 h->rxq = g_renew(char, h->rxq, h->rxlen + 1024); 267 st = read(h->fd, h->rxq + h->rxlen, 1024); 267 268 h->rxlen += st; 268 269 if( st <= 0 ) 270 return( -1 ); 271 272 if( getenv( "BITLBEE_DEBUG" ) ) 273 { 274 write( 2, "->C:", 4 ); 275 write( 2, h->rxq + h->rxlen - st, st ); 276 } 277 278 while( st ) 279 { 269 270 if (st <= 0) { 271 return(-1); 272 } 273 274 if (getenv("BITLBEE_DEBUG")) { 275 write(2, "->C:", 4); 276 write(2, h->rxq + h->rxlen - st, st); 277 } 278 279 while (st) { 280 280 int i; 281 282 if( h->msglen == 0 ) 283 { 284 for( i = 0; i < h->rxlen; i ++ ) 285 { 286 if( h->rxq[i] == '\r' || h->rxq[i] == '\n' ) 287 { 281 282 if (h->msglen == 0) { 283 for (i = 0; i < h->rxlen; i++) { 284 if (h->rxq[i] == '\r' || h->rxq[i] == '\n') { 288 285 char *cmd_text, **cmd; 289 286 int count; 290 291 cmd_text = g_strndup( h->rxq, i ); 292 cmd = msn_linesplit( cmd_text ); 293 for( count = 0; cmd[count]; count ++ ); 294 st = h->exec_command( h, cmd, count ); 295 g_free( cmd_text ); 296 287 288 cmd_text = g_strndup(h->rxq, i); 289 cmd = msn_linesplit(cmd_text); 290 for (count = 0; cmd[count]; count++) { 291 ; 292 } 293 st = h->exec_command(h, cmd, count); 294 g_free(cmd_text); 295 297 296 /* If the connection broke, don't continue. We don't even exist anymore. */ 298 if( !st ) 299 return( 0 ); 300 301 if( h->msglen ) 302 h->cmd_text = g_strndup( h->rxq, i ); 303 297 if (!st) { 298 return(0); 299 } 300 301 if (h->msglen) { 302 h->cmd_text = g_strndup(h->rxq, i); 303 } 304 304 305 /* Skip to the next non-emptyline */ 305 while( i < h->rxlen && ( h->rxq[i] == '\r' || h->rxq[i] == '\n' ) ) i ++; 306 306 while (i < h->rxlen && (h->rxq[i] == '\r' || h->rxq[i] == '\n')) { 307 i++; 308 } 309 307 310 break; 308 311 } 309 312 } 310 313 311 314 /* If we reached the end of the buffer, there's still an incomplete command there. 312 315 Return and wait for more data. */ 313 if ( i == h->rxlen && h->rxq[i-1] != '\r' && h->rxq[i-1] != '\n' )316 if (i == h->rxlen && h->rxq[i - 1] != '\r' && h->rxq[i - 1] != '\n') { 314 317 break; 315 } 316 else 317 { 318 } 319 } else { 318 320 char *msg, **cmd; 319 321 int count; 320 322 321 323 /* Do we have the complete message already? */ 322 if ( h->msglen > h->rxlen )324 if (h->msglen > h->rxlen) { 323 325 break; 324 325 msg = g_strndup( h->rxq, h->msglen ); 326 cmd = msn_linesplit( h->cmd_text ); 327 for( count = 0; cmd[count]; count ++ ); 328 329 st = h->exec_message( h, msg, h->msglen, cmd, count ); 330 g_free( msg ); 331 g_free( h->cmd_text ); 326 } 327 328 msg = g_strndup(h->rxq, h->msglen); 329 cmd = msn_linesplit(h->cmd_text); 330 for (count = 0; cmd[count]; count++) { 331 ; 332 } 333 334 st = h->exec_message(h, msg, h->msglen, cmd, count); 335 g_free(msg); 336 g_free(h->cmd_text); 332 337 h->cmd_text = NULL; 333 334 if( !st ) 335 return( 0 ); 336 338 339 if (!st) { 340 return(0); 341 } 342 337 343 i = h->msglen; 338 344 h->msglen = 0; 339 345 } 340 346 341 347 /* More data after this block? */ 342 if( i < h->rxlen ) 343 { 348 if (i < h->rxlen) { 344 349 char *tmp; 345 346 tmp = g_memdup( h->rxq + i, h->rxlen - i);347 g_free( h->rxq);350 351 tmp = g_memdup(h->rxq + i, h->rxlen - i); 352 g_free(h->rxq); 348 353 h->rxq = tmp; 349 354 h->rxlen -= i; 350 355 i = 0; 351 } 352 else 353 /* If not, reset the rx queue and get lost. */ 354 { 355 g_free( h->rxq ); 356 h->rxq = g_new0( char, 1 ); 356 } else { 357 /* If not, reset the rx queue and get lost. */ 358 g_free(h->rxq); 359 h->rxq = g_new0(char, 1); 357 360 h->rxlen = 0; 358 return( 1);359 } 360 } 361 362 return( 1);363 } 364 365 void msn_msgq_purge( struct im_connection *ic, GSList **list)361 return(1); 362 } 363 } 364 365 return(1); 366 } 367 368 void msn_msgq_purge(struct im_connection *ic, GSList **list) 366 369 { 367 370 struct msn_message *m; … … 369 372 GSList *l; 370 373 int n = 0; 371 374 372 375 l = *list; 373 if ( l == NULL )376 if (l == NULL) { 374 377 return; 375 378 } 379 376 380 m = l->data; 377 ret = g_string_sized_new( 1024 ); 378 g_string_printf( ret, "Warning: Cleaning up MSN (switchboard) connection with unsent " 379 "messages to %s:", m->who ? m->who : "unknown recipient" ); 380 381 while( l ) 382 { 381 ret = g_string_sized_new(1024); 382 g_string_printf(ret, "Warning: Cleaning up MSN (switchboard) connection with unsent " 383 "messages to %s:", m->who ? m->who : "unknown recipient"); 384 385 while (l) { 383 386 m = l->data; 384 385 if( strncmp( m->text, "\r\r\r", 3 ) != 0 ) 386 { 387 g_string_append_printf( ret, "\n%s", m->text ); 388 n ++; 389 } 390 391 g_free( m->who ); 392 g_free( m->text ); 393 g_free( m ); 394 387 388 if (strncmp(m->text, "\r\r\r", 3) != 0) { 389 g_string_append_printf(ret, "\n%s", m->text); 390 n++; 391 } 392 393 g_free(m->who); 394 g_free(m->text); 395 g_free(m); 396 395 397 l = l->next; 396 398 } 397 g_slist_free( *list);399 g_slist_free(*list); 398 400 *list = NULL; 399 400 if( n > 0 ) 401 imcb_log( ic, "%s", ret->str ); 402 g_string_free( ret, TRUE ); 401 402 if (n > 0) { 403 imcb_log(ic, "%s", ret->str); 404 } 405 g_string_free(ret, TRUE); 403 406 } 404 407 405 408 /* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */ 406 char *msn_p11_challenge( char *challenge)409 char *msn_p11_challenge(char *challenge) 407 410 { 408 411 char *output, buf[256]; … … 415 418 /* Create the MD5 hash */ 416 419 md5_init(&md5c); 417 md5_append(&md5c, (unsigned char *) challenge, strlen(challenge));418 md5_append(&md5c, (unsigned char *) MSNP11_PROD_KEY, strlen(MSNP11_PROD_KEY));420 md5_append(&md5c, (unsigned char *) challenge, strlen(challenge)); 421 md5_append(&md5c, (unsigned char *) MSNP11_PROD_KEY, strlen(MSNP11_PROD_KEY)); 419 422 md5_finish(&md5c, md5Hash); 420 423 421 424 /* Split it into four integers */ 422 md5Parts = (unsigned int *)md5Hash; 423 for (i = 0; i < 4; i ++) 424 { 425 md5Parts = (unsigned int *) md5Hash; 426 for (i = 0; i < 4; i++) { 425 427 md5Parts[i] = GUINT32_TO_LE(md5Parts[i]); 426 428 427 429 /* & each integer with 0x7FFFFFFF */ 428 430 /* and save one unmodified array for later */ … … 430 432 md5Parts[i] &= 0x7FFFFFFF; 431 433 } 432 434 433 435 /* make a new string and pad with '0' */ 434 n = g_snprintf(buf, sizeof(buf) -5, "%s%s00000000", challenge, MSNP11_PROD_ID);436 n = g_snprintf(buf, sizeof(buf) - 5, "%s%s00000000", challenge, MSNP11_PROD_ID); 435 437 /* truncate at an 8-byte boundary */ 436 buf[n &=~7] = '\0';437 438 buf[n &= ~7] = '\0'; 439 438 440 /* split into integers */ 439 chlStringParts = (unsigned int *) buf;440 441 chlStringParts = (unsigned int *) buf; 442 441 443 /* this is magic */ 442 for (i = 0; i < (n / 4) - 1; i += 2) 443 { 444 for (i = 0; i < (n / 4) - 1; i += 2) { 444 445 long long temp; 445 446 446 447 chlStringParts[i] = GUINT32_TO_LE(chlStringParts[i]); 447 chlStringParts[i+1] = GUINT32_TO_LE(chlStringParts[i+1]); 448 449 temp = (md5Parts[0] * (((0x0E79A9C1 * (long long)chlStringParts[i]) % 0x7FFFFFFF)+nHigh) + md5Parts[1])%0x7FFFFFFF; 450 nHigh = (md5Parts[2] * (((long long)chlStringParts[i+1]+temp) % 0x7FFFFFFF) + md5Parts[3]) % 0x7FFFFFFF; 448 chlStringParts[i + 1] = GUINT32_TO_LE(chlStringParts[i + 1]); 449 450 temp = 451 (md5Parts[0] * 452 (((0x0E79A9C1 * 453 (long long) chlStringParts[i]) % 0x7FFFFFFF) + nHigh) + md5Parts[1]) % 0x7FFFFFFF; 454 nHigh = 455 (md5Parts[2] * 456 (((long long) chlStringParts[i + 1] + temp) % 0x7FFFFFFF) + md5Parts[3]) % 0x7FFFFFFF; 451 457 nLow = nLow + nHigh + temp; 452 458 } 453 nHigh = (nHigh +md5Parts[1]) % 0x7FFFFFFF;454 nLow = (nLow +md5Parts[3]) % 0x7FFFFFFF;455 459 nHigh = (nHigh + md5Parts[1]) % 0x7FFFFFFF; 460 nLow = (nLow + md5Parts[3]) % 0x7FFFFFFF; 461 456 462 newHashParts[0] ^= nHigh; 457 463 newHashParts[1] ^= nLow; 458 464 newHashParts[2] ^= nHigh; 459 465 newHashParts[3] ^= nLow; 460 466 461 467 /* swap more bytes if big endian */ 462 for (i = 0; i < 4; i ++) 463 newHashParts[i] = GUINT32_TO_LE(newHashParts[i]); 464 468 for (i = 0; i < 4; i++) { 469 newHashParts[i] = GUINT32_TO_LE(newHashParts[i]); 470 } 471 465 472 /* make a string of the parts */ 466 newHash = (unsigned char *) newHashParts;467 473 newHash = (unsigned char *) newHashParts; 474 468 475 /* convert to hexadecimal */ 469 476 output = g_new(char, 33); 470 for (i = 0; i < 16; i ++)477 for (i = 0; i < 16; i++) { 471 478 sprintf(output + i * 2, "%02x", newHash[i]); 472 479 } 480 473 481 return output; 474 482 } 475 483 476 gint msn_domaintree_cmp( gconstpointer a_, gconstpointer b_)484 gint msn_domaintree_cmp(gconstpointer a_, gconstpointer b_) 477 485 { 478 486 const char *a = a_, *b = b_; 479 487 gint ret; 480 481 if( !( a = strchr( a, '@' ) ) || !( b = strchr( b, '@' ) ) || 482 ( ret = strcmp( a, b ) ) == 0 ) 483 ret = strcmp( a_, b_ ); 484 488 489 if (!(a = strchr(a, '@')) || !(b = strchr(b, '@')) || 490 (ret = strcmp(a, b)) == 0) { 491 ret = strcmp(a_, b_); 492 } 493 485 494 return ret; 486 495 } 487 496 488 struct msn_group *msn_group_by_name( struct im_connection *ic, const char *name)497 struct msn_group *msn_group_by_name(struct im_connection *ic, const char *name) 489 498 { 490 499 struct msn_data *md = ic->proto_data; 491 500 GSList *l; 492 493 for( l = md->groups; l; l = l->next ) 494 { 501 502 for (l = md->groups; l; l = l->next) { 495 503 struct msn_group *mg = l->data; 496 497 if ( g_strcasecmp( mg->name, name ) == 0 )504 505 if (g_strcasecmp(mg->name, name) == 0) { 498 506 return mg; 499 } 500 507 } 508 } 509 501 510 return NULL; 502 511 } 503 512 504 struct msn_group *msn_group_by_id( struct im_connection *ic, const char *id)513 struct msn_group *msn_group_by_id(struct im_connection *ic, const char *id) 505 514 { 506 515 struct msn_data *md = ic->proto_data; 507 516 GSList *l; 508 509 for( l = md->groups; l; l = l->next ) 510 { 517 518 for (l = md->groups; l; l = l->next) { 511 519 struct msn_group *mg = l->data; 512 513 if ( g_strcasecmp( mg->id, id ) == 0 )520 521 if (g_strcasecmp(mg->id, id) == 0) { 514 522 return mg; 515 } 516 523 } 524 } 525 517 526 return NULL; 518 527 } 519 528 520 int msn_ns_set_display_name( struct im_connection *ic, const char *value)529 int msn_ns_set_display_name(struct im_connection *ic, const char *value) 521 530 { 522 531 struct msn_data *md = ic->proto_data; 523 char fn[strlen(value) *3+1];524 525 strcpy( fn, value);526 http_encode( fn);527 532 char fn[strlen(value) * 3 + 1]; 533 534 strcpy(fn, value); 535 http_encode(fn); 536 528 537 /* Note: We don't actually know if the server accepted the new name, 529 538 and won't give proper feedback yet if it doesn't. */ 530 return msn_ns_write( ic, -1, "PRP %d MFN %s\r\n", ++md->trId, fn);531 } 532 533 const char *msn_normalize_handle( const char *handle)534 { 535 if ( strncmp( handle, "1:", 2 ) == 0 )539 return msn_ns_write(ic, -1, "PRP %d MFN %s\r\n", ++md->trId, fn); 540 } 541 542 const char *msn_normalize_handle(const char *handle) 543 { 544 if (strncmp(handle, "1:", 2) == 0) { 536 545 return handle + 2; 537 else546 } else { 538 547 return handle; 539 } 548 } 549 } -
protocols/msn/ns.c
raf359b4 r5ebff60 1 1 /********************************************************************\ 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * … … 33 33 #include "xmltree.h" 34 34 35 static gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond);36 static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond);37 static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num_parts);38 static int msn_ns_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts);39 40 static void msn_ns_send_adl_start( struct im_connection *ic);41 static void msn_ns_send_adl( struct im_connection *ic);42 43 int msn_ns_write( struct im_connection *ic, int fd, const char *fmt, ...)35 static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond); 36 static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond); 37 static int msn_ns_command(struct msn_handler_data *handler, char **cmd, int num_parts); 38 static int msn_ns_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts); 39 40 static void msn_ns_send_adl_start(struct im_connection *ic); 41 static void msn_ns_send_adl(struct im_connection *ic); 42 43 int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...) 44 44 { 45 45 struct msn_data *md = ic->proto_data; … … 48 48 size_t len; 49 49 int st; 50 51 va_start( params, fmt);52 out = g_strdup_vprintf( fmt, params);53 va_end( params);54 55 if ( fd < 0 )50 51 va_start(params, fmt); 52 out = g_strdup_vprintf(fmt, params); 53 va_end(params); 54 55 if (fd < 0) { 56 56 fd = md->ns->fd; 57 58 if( getenv( "BITLBEE_DEBUG" ) ) 59 fprintf( stderr, "->NS%d:%s\n", fd, out ); 60 61 len = strlen( out ); 62 st = write( fd, out, len ); 63 g_free( out ); 64 if( st != len ) 65 { 66 imcb_error( ic, "Short write() to main server" ); 67 imc_logout( ic, TRUE ); 57 } 58 59 if (getenv("BITLBEE_DEBUG")) { 60 fprintf(stderr, "->NS%d:%s\n", fd, out); 61 } 62 63 len = strlen(out); 64 st = write(fd, out, len); 65 g_free(out); 66 if (st != len) { 67 imcb_error(ic, "Short write() to main server"); 68 imc_logout(ic, TRUE); 68 69 return 0; 69 70 } 70 71 71 72 return 1; 72 73 } 73 74 74 gboolean msn_ns_connect( struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port ) 75 { 76 if( handler->fd >= 0 ) 77 closesocket( handler->fd ); 78 75 gboolean msn_ns_connect(struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port) 76 { 77 if (handler->fd >= 0) { 78 closesocket(handler->fd); 79 } 80 79 81 handler->exec_command = msn_ns_command; 80 82 handler->exec_message = msn_ns_message; 81 83 handler->data = ic; 82 handler->fd = proxy_connect( host, port, msn_ns_connected, handler ); 83 if( handler->fd < 0 ) 84 { 85 imcb_error( ic, "Could not connect to server" ); 86 imc_logout( ic, TRUE ); 84 handler->fd = proxy_connect(host, port, msn_ns_connected, handler); 85 if (handler->fd < 0) { 86 imcb_error(ic, "Could not connect to server"); 87 imc_logout(ic, TRUE); 87 88 return FALSE; 88 89 } 89 90 90 91 return TRUE; 91 92 } 92 93 93 static gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond)94 static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond) 94 95 { 95 96 struct msn_handler_data *handler = data; 96 97 struct im_connection *ic = handler->data; 97 98 struct msn_data *md; 98 99 if ( !g_slist_find( msn_connections, ic ) )99 100 if (!g_slist_find(msn_connections, ic)) { 100 101 return FALSE; 101 102 } 103 102 104 md = ic->proto_data; 103 104 if( source == -1 ) 105 { 106 imcb_error( ic, "Could not connect to server" ); 107 imc_logout( ic, TRUE ); 105 106 if (source == -1) { 107 imcb_error(ic, "Could not connect to server"); 108 imc_logout(ic, TRUE); 108 109 return FALSE; 109 110 } 110 111 g_free( handler->rxq);111 112 g_free(handler->rxq); 112 113 handler->rxlen = 0; 113 handler->rxq = g_new0( char, 1 ); 114 115 if( md->uuid == NULL ) 116 { 114 handler->rxq = g_new0(char, 1); 115 116 if (md->uuid == NULL) { 117 117 struct utsname name; 118 118 sha1_state_t sha[1]; 119 119 120 120 /* UUID == SHA1("BitlBee" + my hostname + MSN username) */ 121 sha1_init( sha ); 122 sha1_append( sha, (void*) "BitlBee", 7 ); 123 if( uname( &name ) == 0 ) 124 { 125 sha1_append( sha, (void*) name.nodename, strlen( name.nodename ) ); 126 } 127 sha1_append( sha, (void*) ic->acc->user, strlen( ic->acc->user ) ); 128 md->uuid = sha1_random_uuid( sha ); 129 memcpy( md->uuid, "b171be3e", 8 ); /* :-P */ 130 } 131 132 if( msn_ns_write( ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER ) ) 133 { 134 handler->inpa = b_input_add( handler->fd, B_EV_IO_READ, msn_ns_callback, handler ); 135 imcb_log( ic, "Connected to server, waiting for reply" ); 136 } 137 121 sha1_init(sha); 122 sha1_append(sha, (void *) "BitlBee", 7); 123 if (uname(&name) == 0) { 124 sha1_append(sha, (void *) name.nodename, strlen(name.nodename)); 125 } 126 sha1_append(sha, (void *) ic->acc->user, strlen(ic->acc->user)); 127 md->uuid = sha1_random_uuid(sha); 128 memcpy(md->uuid, "b171be3e", 8); /* :-P */ 129 } 130 131 if (msn_ns_write(ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER)) { 132 handler->inpa = b_input_add(handler->fd, B_EV_IO_READ, msn_ns_callback, handler); 133 imcb_log(ic, "Connected to server, waiting for reply"); 134 } 135 138 136 return FALSE; 139 137 } 140 138 141 void msn_ns_close( struct msn_handler_data *handler ) 142 { 143 if( handler->fd >= 0 ) 144 { 145 closesocket( handler->fd ); 146 b_event_remove( handler->inpa ); 147 } 148 139 void msn_ns_close(struct msn_handler_data *handler) 140 { 141 if (handler->fd >= 0) { 142 closesocket(handler->fd); 143 b_event_remove(handler->inpa); 144 } 145 149 146 handler->fd = handler->inpa = -1; 150 g_free( handler->rxq);151 g_free( handler->cmd_text);152 147 g_free(handler->rxq); 148 g_free(handler->cmd_text); 149 153 150 handler->rxlen = 0; 154 151 handler->rxq = NULL; … … 156 153 } 157 154 158 static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond)155 static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond) 159 156 { 160 157 struct msn_handler_data *handler = data; 161 158 struct im_connection *ic = handler->data; 162 163 if( msn_handler( handler ) == -1 ) /* Don't do this on ret == 0, it's already done then. */ 164 { 165 imcb_error( ic, "Error while reading from server" ); 166 imc_logout( ic, TRUE ); 167 159 160 if (msn_handler(handler) == -1) { /* Don't do this on ret == 0, it's already done then. */ 161 imcb_error(ic, "Error while reading from server"); 162 imc_logout(ic, TRUE); 163 168 164 return FALSE; 169 } 170 else 165 } else { 171 166 return TRUE; 172 } 173 174 static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num_parts ) 167 } 168 } 169 170 static int msn_ns_command(struct msn_handler_data *handler, char **cmd, int num_parts) 175 171 { 176 172 struct im_connection *ic = handler->data; 177 173 struct msn_data *md = ic->proto_data; 178 179 if( num_parts == 0 ) 180 { 174 175 if (num_parts == 0) { 181 176 /* Hrrm... Empty command...? Ignore? */ 182 return( 1 ); 183 } 184 185 if( strcmp( cmd[0], "VER" ) == 0 ) 186 { 187 if( cmd[2] && strncmp( cmd[2], MSNP_VER, 5 ) != 0 ) 188 { 189 imcb_error( ic, "Unsupported protocol" ); 190 imc_logout( ic, FALSE ); 191 return( 0 ); 192 } 193 194 return( msn_ns_write( ic, handler->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n", 195 ++md->trId, ic->acc->user ) ); 196 } 197 else if( strcmp( cmd[0], "CVR" ) == 0 ) 198 { 177 return(1); 178 } 179 180 if (strcmp(cmd[0], "VER") == 0) { 181 if (cmd[2] && strncmp(cmd[2], MSNP_VER, 5) != 0) { 182 imcb_error(ic, "Unsupported protocol"); 183 imc_logout(ic, FALSE); 184 return(0); 185 } 186 187 return(msn_ns_write(ic, handler->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n", 188 ++md->trId, ic->acc->user)); 189 } else if (strcmp(cmd[0], "CVR") == 0) { 199 190 /* We don't give a damn about the information we just received */ 200 return msn_ns_write( ic, handler->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user ); 201 } 202 else if( strcmp( cmd[0], "XFR" ) == 0 ) 203 { 191 return msn_ns_write(ic, handler->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user); 192 } else if (strcmp(cmd[0], "XFR") == 0) { 204 193 char *server; 205 194 int port; 206 207 if( num_parts >= 6 && strcmp( cmd[2], "NS" ) == 0 ) 208 { 209 b_event_remove( handler->inpa ); 195 196 if (num_parts >= 6 && strcmp(cmd[2], "NS") == 0) { 197 b_event_remove(handler->inpa); 210 198 handler->inpa = -1; 211 212 server = strchr( cmd[3], ':' ); 213 if( !server ) 214 { 215 imcb_error( ic, "Syntax error" ); 216 imc_logout( ic, TRUE ); 217 return( 0 ); 199 200 server = strchr(cmd[3], ':'); 201 if (!server) { 202 imcb_error(ic, "Syntax error"); 203 imc_logout(ic, TRUE); 204 return(0); 218 205 } 219 206 *server = 0; 220 port = atoi( server + 1);207 port = atoi(server + 1); 221 208 server = cmd[3]; 222 223 imcb_log( ic, "Transferring to other server" ); 224 return msn_ns_connect( ic, handler, server, port ); 225 } 226 else if( num_parts >= 6 && strcmp( cmd[2], "SB" ) == 0 ) 227 { 209 210 imcb_log(ic, "Transferring to other server"); 211 return msn_ns_connect(ic, handler, server, port); 212 } else if (num_parts >= 6 && strcmp(cmd[2], "SB") == 0) { 228 213 struct msn_switchboard *sb; 229 230 server = strchr( cmd[3], ':' ); 231 if( !server ) 232 { 233 imcb_error( ic, "Syntax error" ); 234 imc_logout( ic, TRUE ); 235 return( 0 ); 214 215 server = strchr(cmd[3], ':'); 216 if (!server) { 217 imcb_error(ic, "Syntax error"); 218 imc_logout(ic, TRUE); 219 return(0); 236 220 } 237 221 *server = 0; 238 port = atoi( server + 1);222 port = atoi(server + 1); 239 223 server = cmd[3]; 240 241 if( strcmp( cmd[4], "CKI" ) != 0 ) 242 { 243 imcb_error( ic, "Unknown authentication method for switchboard" ); 244 imc_logout( ic, TRUE ); 245 return( 0 ); 246 } 247 248 debug( "Connecting to a new switchboard with key %s", cmd[5] ); 249 250 if( ( sb = msn_sb_create( ic, server, port, cmd[5], MSN_SB_NEW ) ) == NULL ) 251 { 224 225 if (strcmp(cmd[4], "CKI") != 0) { 226 imcb_error(ic, "Unknown authentication method for switchboard"); 227 imc_logout(ic, TRUE); 228 return(0); 229 } 230 231 debug("Connecting to a new switchboard with key %s", cmd[5]); 232 233 if ((sb = msn_sb_create(ic, server, port, cmd[5], MSN_SB_NEW)) == NULL) { 252 234 /* Although this isn't strictly fatal for the NS connection, it's 253 235 definitely something serious (we ran out of file descriptors?). */ 254 imcb_error( ic, "Could not create new switchboard" ); 255 imc_logout( ic, TRUE ); 256 return( 0 ); 257 } 258 259 if( md->msgq ) 260 { 236 imcb_error(ic, "Could not create new switchboard"); 237 imc_logout(ic, TRUE); 238 return(0); 239 } 240 241 if (md->msgq) { 261 242 struct msn_message *m = md->msgq->data; 262 243 GSList *l; 263 264 sb->who = g_strdup( m->who);265 244 245 sb->who = g_strdup(m->who); 246 266 247 /* Move all the messages to the first user in the message 267 248 queue to the switchboard message queue. */ 268 249 l = md->msgq; 269 while( l ) 270 { 250 while (l) { 271 251 m = l->data; 272 252 l = l->next; 273 if( strcmp( m->who, sb->who ) == 0 ) 274 { 275 sb->msgq = g_slist_append( sb->msgq, m ); 276 md->msgq = g_slist_remove( md->msgq, m ); 253 if (strcmp(m->who, sb->who) == 0) { 254 sb->msgq = g_slist_append(sb->msgq, m); 255 md->msgq = g_slist_remove(md->msgq, m); 277 256 } 278 257 } 279 258 } 280 } 281 else 282 { 283 imcb_error( ic, "Syntax error" ); 284 imc_logout( ic, TRUE ); 285 return( 0 ); 286 } 287 } 288 else if( strcmp( cmd[0], "USR" ) == 0 ) 289 { 290 if( num_parts >= 6 && strcmp( cmd[2], "SSO" ) == 0 && 291 strcmp( cmd[3], "S" ) == 0 ) 292 { 293 g_free( md->pp_policy ); 294 md->pp_policy = g_strdup( cmd[4] ); 295 msn_soap_passport_sso_request( ic, cmd[5] ); 296 } 297 else if( strcmp( cmd[2], "OK" ) == 0 ) 298 { 259 } else { 260 imcb_error(ic, "Syntax error"); 261 imc_logout(ic, TRUE); 262 return(0); 263 } 264 } else if (strcmp(cmd[0], "USR") == 0) { 265 if (num_parts >= 6 && strcmp(cmd[2], "SSO") == 0 && 266 strcmp(cmd[3], "S") == 0) { 267 g_free(md->pp_policy); 268 md->pp_policy = g_strdup(cmd[4]); 269 msn_soap_passport_sso_request(ic, cmd[5]); 270 } else if (strcmp(cmd[2], "OK") == 0) { 299 271 /* If the number after the handle is 0, the e-mail 300 272 address is unverified, which means we can't change 301 273 the display name. */ 302 if ( cmd[4][0] == '0' )274 if (cmd[4][0] == '0') { 303 275 md->flags |= MSN_EMAIL_UNVERIFIED; 304 305 imcb_log( ic, "Authenticated, getting buddy list" ); 306 msn_soap_memlist_request( ic ); 307 } 308 else 309 { 310 imcb_error( ic, "Unknown authentication type" ); 311 imc_logout( ic, FALSE ); 312 return( 0 ); 313 } 314 } 315 else if( strcmp( cmd[0], "MSG" ) == 0 ) 316 { 317 if( num_parts < 4 ) 318 { 319 imcb_error( ic, "Syntax error" ); 320 imc_logout( ic, TRUE ); 321 return( 0 ); 322 } 323 324 handler->msglen = atoi( cmd[3] ); 325 326 if( handler->msglen <= 0 ) 327 { 328 imcb_error( ic, "Syntax error" ); 329 imc_logout( ic, TRUE ); 330 return( 0 ); 331 } 332 } 333 else if( strcmp( cmd[0], "BLP" ) == 0 ) 334 { 335 msn_ns_send_adl_start( ic ); 336 return msn_ns_finish_login( ic ); 337 } 338 else if( strcmp( cmd[0], "ADL" ) == 0 ) 339 { 340 if( num_parts >= 3 && strcmp( cmd[2], "OK" ) == 0 ) 341 { 342 msn_ns_send_adl( ic ); 343 return msn_ns_finish_login( ic ); 344 } 345 else if( num_parts >= 3 ) 346 { 347 handler->msglen = atoi( cmd[2] ); 348 } 349 } 350 else if( strcmp( cmd[0], "PRP" ) == 0 ) 351 { 352 imcb_connected( ic ); 353 } 354 else if( strcmp( cmd[0], "CHL" ) == 0 ) 355 { 276 } 277 278 imcb_log(ic, "Authenticated, getting buddy list"); 279 msn_soap_memlist_request(ic); 280 } else { 281 imcb_error(ic, "Unknown authentication type"); 282 imc_logout(ic, FALSE); 283 return(0); 284 } 285 } else if (strcmp(cmd[0], "MSG") == 0) { 286 if (num_parts < 4) { 287 imcb_error(ic, "Syntax error"); 288 imc_logout(ic, TRUE); 289 return(0); 290 } 291 292 handler->msglen = atoi(cmd[3]); 293 294 if (handler->msglen <= 0) { 295 imcb_error(ic, "Syntax error"); 296 imc_logout(ic, TRUE); 297 return(0); 298 } 299 } else if (strcmp(cmd[0], "BLP") == 0) { 300 msn_ns_send_adl_start(ic); 301 return msn_ns_finish_login(ic); 302 } else if (strcmp(cmd[0], "ADL") == 0) { 303 if (num_parts >= 3 && strcmp(cmd[2], "OK") == 0) { 304 msn_ns_send_adl(ic); 305 return msn_ns_finish_login(ic); 306 } else if (num_parts >= 3) { 307 handler->msglen = atoi(cmd[2]); 308 } 309 } else if (strcmp(cmd[0], "PRP") == 0) { 310 imcb_connected(ic); 311 } else if (strcmp(cmd[0], "CHL") == 0) { 356 312 char *resp; 357 313 int st; 358 359 if( num_parts < 3 ) 360 { 361 imcb_error( ic, "Syntax error" ); 362 imc_logout( ic, TRUE ); 363 return( 0 ); 364 } 365 366 resp = msn_p11_challenge( cmd[2] ); 367 368 st = msn_ns_write( ic, -1, "QRY %d %s %zd\r\n%s", 369 ++md->trId, MSNP11_PROD_ID, 370 strlen( resp ), resp ); 371 g_free( resp ); 314 315 if (num_parts < 3) { 316 imcb_error(ic, "Syntax error"); 317 imc_logout(ic, TRUE); 318 return(0); 319 } 320 321 resp = msn_p11_challenge(cmd[2]); 322 323 st = msn_ns_write(ic, -1, "QRY %d %s %zd\r\n%s", 324 ++md->trId, MSNP11_PROD_ID, 325 strlen(resp), resp); 326 g_free(resp); 372 327 return st; 373 } 374 else if( strcmp( cmd[0], "ILN" ) == 0 || strcmp( cmd[0], "NLN" ) == 0 ) 375 { 328 } else if (strcmp(cmd[0], "ILN") == 0 || strcmp(cmd[0], "NLN") == 0) { 376 329 const struct msn_away_state *st; 377 330 const char *handle; 378 331 int cap = 0; 379 380 if( num_parts < 6 ) 381 { 382 imcb_error( ic, "Syntax error" ); 383 imc_logout( ic, TRUE ); 384 return( 0 ); 332 333 if (num_parts < 6) { 334 imcb_error(ic, "Syntax error"); 335 imc_logout(ic, TRUE); 336 return(0); 385 337 } 386 338 /* ILN and NLN are more or less the same, except ILN has a trId 387 at the start, and NLN has a capability field at the end. 339 at the start, and NLN has a capability field at the end. 388 340 Does ILN still exist BTW? */ 389 if( cmd[0][1] == 'I' ) 390 cmd ++; 391 else 392 cap = atoi( cmd[4] ); 393 394 handle = msn_normalize_handle( cmd[2] ); 395 if( strcmp( handle, ic->acc->user ) == 0 ) 341 if (cmd[0][1] == 'I') { 342 cmd++; 343 } else { 344 cap = atoi(cmd[4]); 345 } 346 347 handle = msn_normalize_handle(cmd[2]); 348 if (strcmp(handle, ic->acc->user) == 0) { 396 349 return 1; /* That's me! */ 397 398 http_decode( cmd[3] );399 imcb_rename_buddy( ic, handle, cmd[3]);400 401 st = msn_away_state_by_code( cmd[1] ); 402 if( !st )403 {350 351 } 352 http_decode(cmd[3]); 353 imcb_rename_buddy(ic, handle, cmd[3]); 354 355 st = msn_away_state_by_code(cmd[1]); 356 if (!st) { 404 357 /* FIXME: Warn/Bomb about unknown away state? */ 405 358 st = msn_away_state_list + 1; 406 359 } 407 408 imcb_buddy_status( ic, handle, OPT_LOGGED_IN | 409 ( st != msn_away_state_list ? OPT_AWAY : 0 ) | 410 ( cap & 1 ? OPT_MOBILE : 0 ), 411 st->name, NULL ); 412 413 msn_sb_stop_keepalives( msn_sb_by_handle( ic, handle ) ); 414 } 415 else if( strcmp( cmd[0], "FLN" ) == 0 ) 416 { 360 361 imcb_buddy_status(ic, handle, OPT_LOGGED_IN | 362 (st != msn_away_state_list ? OPT_AWAY : 0) | 363 (cap & 1 ? OPT_MOBILE : 0), 364 st->name, NULL); 365 366 msn_sb_stop_keepalives(msn_sb_by_handle(ic, handle)); 367 } else if (strcmp(cmd[0], "FLN") == 0) { 417 368 const char *handle; 418 419 if ( cmd[1] == NULL )369 370 if (cmd[1] == NULL) { 420 371 return 1; 421 422 handle = msn_normalize_handle( cmd[1] ); 423 imcb_buddy_status( ic, handle, 0, NULL, NULL ); 424 msn_sb_start_keepalives( msn_sb_by_handle( ic, handle ), TRUE ); 425 } 426 else if( strcmp( cmd[0], "RNG" ) == 0 ) 427 { 372 } 373 374 handle = msn_normalize_handle(cmd[1]); 375 imcb_buddy_status(ic, handle, 0, NULL, NULL); 376 msn_sb_start_keepalives(msn_sb_by_handle(ic, handle), TRUE); 377 } else if (strcmp(cmd[0], "RNG") == 0) { 428 378 struct msn_switchboard *sb; 429 379 char *server; 430 380 int session, port; 431 432 if( num_parts < 7 ) 433 { 434 imcb_error( ic, "Syntax error" ); 435 imc_logout( ic, TRUE ); 436 return( 0 ); 437 } 438 439 session = atoi( cmd[1] ); 440 441 server = strchr( cmd[2], ':' ); 442 if( !server ) 443 { 444 imcb_error( ic, "Syntax error" ); 445 imc_logout( ic, TRUE ); 446 return( 0 ); 381 382 if (num_parts < 7) { 383 imcb_error(ic, "Syntax error"); 384 imc_logout(ic, TRUE); 385 return(0); 386 } 387 388 session = atoi(cmd[1]); 389 390 server = strchr(cmd[2], ':'); 391 if (!server) { 392 imcb_error(ic, "Syntax error"); 393 imc_logout(ic, TRUE); 394 return(0); 447 395 } 448 396 *server = 0; 449 port = atoi( server + 1);397 port = atoi(server + 1); 450 398 server = cmd[2]; 451 452 if( strcmp( cmd[3], "CKI" ) != 0 ) 453 { 454 imcb_error( ic, "Unknown authentication method for switchboard" ); 455 imc_logout( ic, TRUE ); 456 return( 0 ); 457 } 458 459 debug( "Got a call from %s (session %d). Key = %s", cmd[5], session, cmd[4] ); 460 461 if( ( sb = msn_sb_create( ic, server, port, cmd[4], session ) ) == NULL ) 462 { 399 400 if (strcmp(cmd[3], "CKI") != 0) { 401 imcb_error(ic, "Unknown authentication method for switchboard"); 402 imc_logout(ic, TRUE); 403 return(0); 404 } 405 406 debug("Got a call from %s (session %d). Key = %s", cmd[5], session, cmd[4]); 407 408 if ((sb = msn_sb_create(ic, server, port, cmd[4], session)) == NULL) { 463 409 /* Although this isn't strictly fatal for the NS connection, it's 464 410 definitely something serious (we ran out of file descriptors?). */ 465 imcb_error( ic, "Could not create new switchboard" ); 466 imc_logout( ic, TRUE ); 467 return( 0 ); 468 } 469 else 470 { 471 sb->who = g_strdup( msn_normalize_handle( cmd[5] ) ); 472 } 473 } 474 else if( strcmp( cmd[0], "OUT" ) == 0 ) 475 { 411 imcb_error(ic, "Could not create new switchboard"); 412 imc_logout(ic, TRUE); 413 return(0); 414 } else { 415 sb->who = g_strdup(msn_normalize_handle(cmd[5])); 416 } 417 } else if (strcmp(cmd[0], "OUT") == 0) { 476 418 int allow_reconnect = TRUE; 477 478 if( cmd[1] && strcmp( cmd[1], "OTH" ) == 0 ) 479 { 480 imcb_error( ic, "Someone else logged in with your account" ); 419 420 if (cmd[1] && strcmp(cmd[1], "OTH") == 0) { 421 imcb_error(ic, "Someone else logged in with your account"); 481 422 allow_reconnect = FALSE; 482 } 483 else if( cmd[1] && strcmp( cmd[1], "SSD" ) == 0 ) 484 { 485 imcb_error( ic, "Terminating session because of server shutdown" ); 486 } 487 else 488 { 489 imcb_error( ic, "Session terminated by remote server (%s)", 490 cmd[1] ? cmd[1] : "reason unknown)" ); 491 } 492 493 imc_logout( ic, allow_reconnect ); 494 return( 0 ); 495 } 496 else if( strcmp( cmd[0], "IPG" ) == 0 ) 497 { 498 imcb_error( ic, "Received IPG command, we don't handle them yet." ); 499 500 handler->msglen = atoi( cmd[1] ); 501 502 if( handler->msglen <= 0 ) 503 { 504 imcb_error( ic, "Syntax error" ); 505 imc_logout( ic, TRUE ); 506 return( 0 ); 423 } else if (cmd[1] && strcmp(cmd[1], "SSD") == 0) { 424 imcb_error(ic, "Terminating session because of server shutdown"); 425 } else { 426 imcb_error(ic, "Session terminated by remote server (%s)", 427 cmd[1] ? cmd[1] : "reason unknown)"); 428 } 429 430 imc_logout(ic, allow_reconnect); 431 return(0); 432 } else if (strcmp(cmd[0], "IPG") == 0) { 433 imcb_error(ic, "Received IPG command, we don't handle them yet."); 434 435 handler->msglen = atoi(cmd[1]); 436 437 if (handler->msglen <= 0) { 438 imcb_error(ic, "Syntax error"); 439 imc_logout(ic, TRUE); 440 return(0); 507 441 } 508 442 } 509 443 #if 0 510 else if( strcmp( cmd[0], "ADG" ) == 0 ) 511 { 512 char *group = g_strdup( cmd[3] ); 444 else if (strcmp(cmd[0], "ADG") == 0) { 445 char *group = g_strdup(cmd[3]); 513 446 int groupnum, i; 514 447 GSList *l, *next; 515 516 http_decode( group ); 517 if( sscanf( cmd[4], "%d", &groupnum ) == 1 ) 518 { 519 if( groupnum >= md->groupcount ) 520 { 521 md->grouplist = g_renew( char *, md->grouplist, groupnum + 1 ); 522 for( i = md->groupcount; i <= groupnum; i ++ ) 448 449 http_decode(group); 450 if (sscanf(cmd[4], "%d", &groupnum) == 1) { 451 if (groupnum >= md->groupcount) { 452 md->grouplist = g_renew(char *, md->grouplist, groupnum + 1); 453 for (i = md->groupcount; i <= groupnum; i++) { 523 454 md->grouplist[i] = NULL; 455 } 524 456 md->groupcount = groupnum + 1; 525 457 } 526 g_free( md->grouplist[groupnum]);458 g_free(md->grouplist[groupnum]); 527 459 md->grouplist[groupnum] = group; 528 } 529 else 530 { 460 } else { 531 461 /* Shouldn't happen, but if it does, give up on the group. */ 532 g_free( group);533 imcb_error( ic, "Syntax error");534 imc_logout( ic, TRUE);462 g_free(group); 463 imcb_error(ic, "Syntax error"); 464 imc_logout(ic, TRUE); 535 465 return 0; 536 466 } 537 538 for( l = md->grpq; l; l = next ) 539 { 467 468 for (l = md->grpq; l; l = next) { 540 469 struct msn_groupadd *ga = l->data; 541 470 next = l->next; 542 if( g_strcasecmp( ga->group, group ) == 0 ) 543 { 544 if( !msn_buddy_list_add( ic, "FL", ga->who, ga->who, group ) ) 471 if (g_strcasecmp(ga->group, group) == 0) { 472 if (!msn_buddy_list_add(ic, "FL", ga->who, ga->who, group)) { 545 473 return 0; 546 547 g_free( ga->group ); 548 g_free( ga->who ); 549 g_free( ga ); 550 md->grpq = g_slist_remove( md->grpq, ga ); 474 } 475 476 g_free(ga->group); 477 g_free(ga->who); 478 g_free(ga); 479 md->grpq = g_slist_remove(md->grpq, ga); 551 480 } 552 481 } 553 482 } 554 483 #endif 555 else if( strcmp( cmd[0], "GCF" ) == 0 ) 556 { 484 else if (strcmp(cmd[0], "GCF") == 0) { 557 485 /* Coming up is cmd[2] bytes of stuff we're supposed to 558 486 censore. Meh. */ 559 handler->msglen = atoi( cmd[2] ); 560 } 561 else if( strcmp( cmd[0], "UBX" ) == 0 ) 562 { 487 handler->msglen = atoi(cmd[2]); 488 } else if (strcmp(cmd[0], "UBX") == 0) { 563 489 /* Status message. */ 564 if( num_parts >= 3 ) 565 handler->msglen = atoi( cmd[2] ); 566 } 567 else if( strcmp( cmd[0], "NOT" ) == 0 ) 568 { 490 if (num_parts >= 3) { 491 handler->msglen = atoi(cmd[2]); 492 } 493 } else if (strcmp(cmd[0], "NOT") == 0) { 569 494 /* Some kind of notification, poorly documented but 570 495 apparently used to announce address book changes. */ 571 if( num_parts >= 2 ) 572 handler->msglen = atoi( cmd[1] ); 573 } 574 else if( strcmp( cmd[0], "UBM" ) == 0 ) 575 { 576 if( num_parts >= 7 ) 577 handler->msglen = atoi( cmd[6] ); 578 } 579 else if( strcmp( cmd[0], "QNG" ) == 0 ) 580 { 496 if (num_parts >= 2) { 497 handler->msglen = atoi(cmd[1]); 498 } 499 } else if (strcmp(cmd[0], "UBM") == 0) { 500 if (num_parts >= 7) { 501 handler->msglen = atoi(cmd[6]); 502 } 503 } else if (strcmp(cmd[0], "QNG") == 0) { 581 504 ic->flags |= OPT_PONGED; 582 } 583 else if( g_ascii_isdigit( cmd[0][0] ) ) 584 { 585 int num = atoi( cmd[0] ); 586 const struct msn_status_code *err = msn_status_by_number( num ); 587 588 imcb_error( ic, "Error reported by MSN server: %s", err->text ); 589 590 if( err->flags & STATUS_FATAL ) 591 { 592 imc_logout( ic, TRUE ); 593 return( 0 ); 594 } 595 505 } else if (g_ascii_isdigit(cmd[0][0])) { 506 int num = atoi(cmd[0]); 507 const struct msn_status_code *err = msn_status_by_number(num); 508 509 imcb_error(ic, "Error reported by MSN server: %s", err->text); 510 511 if (err->flags & STATUS_FATAL) { 512 imc_logout(ic, TRUE); 513 return(0); 514 } 515 596 516 /* Oh yes, errors can have payloads too now. Discard them for now. */ 597 if( num_parts >= 3 ) 598 handler->msglen = atoi( cmd[2] ); 599 } 600 else 601 { 517 if (num_parts >= 3) { 518 handler->msglen = atoi(cmd[2]); 519 } 520 } else { 602 521 /* debug( "Received unknown command from main server: %s", cmd[0] ); */ 603 522 } 604 605 return( 1);606 } 607 608 static int msn_ns_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts)523 524 return(1); 525 } 526 527 static int msn_ns_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts) 609 528 { 610 529 struct im_connection *ic = handler->data; 611 530 char *body; 612 531 int blen = 0; 613 614 if ( !num_parts )615 return( 1);616 617 if( ( body = strstr( msg, "\r\n\r\n" ) ) ) 618 {532 533 if (!num_parts) { 534 return(1); 535 } 536 537 if ((body = strstr(msg, "\r\n\r\n"))) { 619 538 body += 4; 620 blen = msglen - ( body - msg ); 621 } 622 623 if( strcmp( cmd[0], "MSG" ) == 0 ) 624 { 625 if( g_strcasecmp( cmd[1], "Hotmail" ) == 0 ) 626 { 627 char *ct = get_rfc822_header( msg, "Content-Type:", msglen ); 628 629 if( !ct ) 630 return( 1 ); 631 632 if( g_strncasecmp( ct, "application/x-msmsgssystemmessage", 33 ) == 0 ) 633 { 539 blen = msglen - (body - msg); 540 } 541 542 if (strcmp(cmd[0], "MSG") == 0) { 543 if (g_strcasecmp(cmd[1], "Hotmail") == 0) { 544 char *ct = get_rfc822_header(msg, "Content-Type:", msglen); 545 546 if (!ct) { 547 return(1); 548 } 549 550 if (g_strncasecmp(ct, "application/x-msmsgssystemmessage", 33) == 0) { 634 551 char *mtype; 635 552 char *arg1; 636 637 if ( !body )638 return( 1);639 640 mtype = get_rfc822_header( body, "Type:", blen ); 641 arg1 = get_rfc822_header( body, "Arg1:", blen);642 643 if( mtype && strcmp( mtype, "1" ) == 0 ) 644 {645 if ( arg1 )646 imcb_log( ic, "The server is going down for maintenance in %s minutes.", arg1 );647 }648 649 g_free( arg1 );650 g_free( mtype ); 651 }652 else if( g_strncasecmp( ct, "text/x-msmsgsprofile", 20 ) == 0 )653 {553 554 if (!body) { 555 return(1); 556 } 557 558 mtype = get_rfc822_header(body, "Type:", blen); 559 arg1 = get_rfc822_header(body, "Arg1:", blen); 560 561 if (mtype && strcmp(mtype, "1") == 0) { 562 if (arg1) { 563 imcb_log(ic, "The server is going down for maintenance in %s minutes.", 564 arg1); 565 } 566 } 567 568 g_free(arg1); 569 g_free(mtype); 570 } else if (g_strncasecmp(ct, "text/x-msmsgsprofile", 20) == 0) { 654 571 /* We don't care about this profile for now... */ 655 } 656 else if( g_strncasecmp( ct, "text/x-msmsgsinitialemailnotification", 37 ) == 0 ) 657 { 658 if( set_getbool( &ic->acc->set, "mail_notifications" ) ) 659 { 660 char *inbox = get_rfc822_header( body, "Inbox-Unread:", blen ); 661 char *folders = get_rfc822_header( body, "Folders-Unread:", blen ); 662 663 if( inbox && folders ) 664 imcb_log( ic, "INBOX contains %s new messages, plus %s messages in other folders.", inbox, folders ); 665 666 g_free( inbox ); 667 g_free( folders ); 668 } 669 } 670 else if( g_strncasecmp( ct, "text/x-msmsgsemailnotification", 30 ) == 0 ) 671 { 672 if( set_getbool( &ic->acc->set, "mail_notifications" ) ) 673 { 674 char *from = get_rfc822_header( body, "From-Addr:", blen ); 675 char *fromname = get_rfc822_header( body, "From:", blen ); 676 677 if( from && fromname ) 678 imcb_log( ic, "Received an e-mail message from %s <%s>.", fromname, from ); 679 680 g_free( from ); 681 g_free( fromname ); 682 } 683 } 684 else if( g_strncasecmp( ct, "text/x-msmsgsactivemailnotification", 35 ) == 0 ) 685 { 686 } 687 else if( g_strncasecmp( ct, "text/x-msmsgsinitialmdatanotification", 37 ) == 0 || 688 g_strncasecmp( ct, "text/x-msmsgsoimnotification", 28 ) == 0 ) 689 { 572 } else if (g_strncasecmp(ct, "text/x-msmsgsinitialemailnotification", 37) == 0) { 573 if (set_getbool(&ic->acc->set, "mail_notifications")) { 574 char *inbox = get_rfc822_header(body, "Inbox-Unread:", blen); 575 char *folders = get_rfc822_header(body, "Folders-Unread:", blen); 576 577 if (inbox && folders) { 578 imcb_log(ic, 579 "INBOX contains %s new messages, plus %s messages in other folders.", inbox, 580 folders); 581 } 582 583 g_free(inbox); 584 g_free(folders); 585 } 586 } else if (g_strncasecmp(ct, "text/x-msmsgsemailnotification", 30) == 0) { 587 if (set_getbool(&ic->acc->set, "mail_notifications")) { 588 char *from = get_rfc822_header(body, "From-Addr:", blen); 589 char *fromname = get_rfc822_header(body, "From:", blen); 590 591 if (from && fromname) { 592 imcb_log(ic, "Received an e-mail message from %s <%s>.", fromname, 593 from); 594 } 595 596 g_free(from); 597 g_free(fromname); 598 } 599 } else if (g_strncasecmp(ct, "text/x-msmsgsactivemailnotification", 35) == 0) { 600 } else if (g_strncasecmp(ct, "text/x-msmsgsinitialmdatanotification", 37) == 0 || 601 g_strncasecmp(ct, "text/x-msmsgsoimnotification", 28) == 0) { 690 602 /* We received an offline message. Or at least notification 691 603 that there is one waiting for us. Fetching the message(s) … … 694 606 have the notification server send them directly, I was 695 607 pretty sure I saw Pidgin do it.. 696 608 697 609 At least give a notification for now, seems like a 698 610 reasonable thing to do. Only problem is, they'll keep 699 611 coming back at login time until you read them using a 700 612 different client. :-( */ 701 702 char *xml = get_rfc822_header( body, "Mail-Data:", blen);613 614 char *xml = get_rfc822_header(body, "Mail-Data:", blen); 703 615 struct xt_node *md, *m; 704 705 if ( !xml )616 617 if (!xml) { 706 618 return 1; 707 md = xt_from_string( xml, 0 ); 708 if( !md ) 619 } 620 md = xt_from_string(xml, 0); 621 if (!md) { 709 622 return 1; 710 711 for( m = md->children; ( m = xt_find_node( m, "M" ) ); m = m->next ) 712 {713 struct xt_node *e = xt_find_node( m->children, "E");714 struct xt_node *rt = xt_find_node( m->children, "RT");623 } 624 625 for (m = md->children; (m = xt_find_node(m, "M")); m = m->next) { 626 struct xt_node *e = xt_find_node(m->children, "E"); 627 struct xt_node *rt = xt_find_node(m->children, "RT"); 715 628 struct tm tp; 716 629 time_t msgtime = 0; 717 718 if ( !e || !e->text )630 631 if (!e || !e->text) { 719 632 continue; 720 721 memset( &tp, 0, sizeof( tp ) ); 722 if( rt && rt->text &&723 sscanf( rt->text, "%4d-%2d-%2dT%2d:%2d:%2d.",724 &tp.tm_year, &tp.tm_mon, &tp.tm_mday,725 &tp.tm_hour, &tp.tm_min, &tp.tm_sec ) == 6 )726 {633 } 634 635 memset(&tp, 0, sizeof(tp)); 636 if (rt && rt->text && 637 sscanf(rt->text, "%4d-%2d-%2dT%2d:%2d:%2d.", 638 &tp.tm_year, &tp.tm_mon, &tp.tm_mday, 639 &tp.tm_hour, &tp.tm_min, &tp.tm_sec) == 6) { 727 640 tp.tm_year -= 1900; 728 tp.tm_mon 729 msgtime = mktime_utc( &tp);730 641 tp.tm_mon--; 642 msgtime = mktime_utc(&tp); 643 731 644 } 732 imcb_buddy_msg( ic, e->text, "<< \002BitlBee\002 - Received offline message. BitlBee can't show these. >>", 0, msgtime ); 733 } 734 735 g_free( xml ); 736 xt_free_node( md ); 737 } 738 else 739 { 740 debug( "Can't handle %s packet from notification server", ct ); 741 } 742 743 g_free( ct ); 744 } 745 } 746 else if( strcmp( cmd[0], "UBX" ) == 0 ) 747 { 645 imcb_buddy_msg(ic, e->text, 646 "<< \002BitlBee\002 - Received offline message. BitlBee can't show these. >>", 0, 647 msgtime); 648 } 649 650 g_free(xml); 651 xt_free_node(md); 652 } else { 653 debug("Can't handle %s packet from notification server", ct); 654 } 655 656 g_free(ct); 657 } 658 } else if (strcmp(cmd[0], "UBX") == 0) { 748 659 struct xt_node *ubx, *psm; 749 660 char *psm_text = NULL; 750 751 ubx = xt_from_string( msg, msglen);752 if ( ubx && strcmp( ubx->name, "Data") == 0 &&753 ( psm = xt_find_node( ubx->children, "PSM" ) ) )661 662 ubx = xt_from_string(msg, msglen); 663 if (ubx && strcmp(ubx->name, "Data") == 0 && 664 (psm = xt_find_node(ubx->children, "PSM"))) { 754 665 psm_text = psm->text; 755 756 imcb_buddy_status_msg( ic, msn_normalize_handle( cmd[1] ), psm_text ); 757 xt_free_node( ubx ); 758 } 759 else if( strcmp( cmd[0], "ADL" ) == 0 ) 760 { 666 } 667 668 imcb_buddy_status_msg(ic, msn_normalize_handle(cmd[1]), psm_text); 669 xt_free_node(ubx); 670 } else if (strcmp(cmd[0], "ADL") == 0) { 761 671 struct xt_node *adl, *d, *c; 762 763 if ( !( adl = xt_from_string( msg, msglen ) ) )672 673 if (!(adl = xt_from_string(msg, msglen))) { 764 674 return 1; 765 766 for( d = adl->children; d; d = d->next ) 767 {675 } 676 677 for (d = adl->children; d; d = d->next) { 768 678 char *dn; 769 if ( strcmp( d->name, "d") != 0 ||770 ( dn = xt_find_attr( d, "n" ) ) == NULL )679 if (strcmp(d->name, "d") != 0 || 680 (dn = xt_find_attr(d, "n")) == NULL) { 771 681 continue; 772 for( c = d->children; c; c = c->next )773 {682 } 683 for (c = d->children; c; c = c->next) { 774 684 bee_user_t *bu; 775 685 struct msn_buddy_data *bd; 776 686 char *cn, *handle, *f, *l; 777 687 int flags; 778 779 if ( strcmp( c->name, "c") != 0 ||780 ( l = xt_find_attr( c, "l" )) == NULL ||781 ( cn = xt_find_attr( c, "n" ) ) == NULL )688 689 if (strcmp(c->name, "c") != 0 || 690 (l = xt_find_attr(c, "l")) == NULL || 691 (cn = xt_find_attr(c, "n")) == NULL) { 782 692 continue; 783 693 } 694 784 695 /* FIXME: Use "t" here, guess I should just add it 785 696 as a prefix like elsewhere in the protocol. */ 786 handle = g_strdup_printf( "%s@%s", cn, dn ); 787 if( !( ( bu = bee_user_by_handle( ic->bee, ic, handle ) ) || 788 ( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) ) ) 789 { 790 g_free( handle ); 697 handle = g_strdup_printf("%s@%s", cn, dn); 698 if (!((bu = bee_user_by_handle(ic->bee, ic, handle)) || 699 (bu = bee_user_new(ic->bee, ic, handle, 0)))) { 700 g_free(handle); 791 701 continue; 792 702 } 793 g_free( handle);703 g_free(handle); 794 704 bd = bu->data; 795 796 if( ( f = xt_find_attr( c, "f" ) ) ) 797 { 798 http_decode( f ); 799 imcb_rename_buddy( ic, bu->handle, f ); 800 } 801 802 flags = atoi( l ) & 15; 803 if( bd->flags != flags ) 804 { 705 706 if ((f = xt_find_attr(c, "f"))) { 707 http_decode(f); 708 imcb_rename_buddy(ic, bu->handle, f); 709 } 710 711 flags = atoi(l) & 15; 712 if (bd->flags != flags) { 805 713 bd->flags = flags; 806 msn_buddy_ask( bu ); 807 } 808 } 809 } 810 } 811 else if( strcmp( cmd[0], "UBM" ) == 0 ) 812 { 714 msn_buddy_ask(bu); 715 } 716 } 717 } 718 } else if (strcmp(cmd[0], "UBM") == 0) { 813 719 /* This one will give us msgs from federated networks. Technically 814 720 it should also get us offline messages, but I don't know how 815 721 I can signal MSN servers to use it. */ 816 722 char *ct, *handle; 817 818 if( strcmp( cmd[1], ic->acc->user ) == 0 ) 819 { 723 724 if (strcmp(cmd[1], ic->acc->user) == 0) { 820 725 /* With MPOP, you'll get copies of your own msgs from other 821 726 sessions. Discard those at least for now. */ 822 727 return 1; 823 728 } 824 825 ct = get_rfc822_header( msg, "Content-Type", msglen ); 826 if( strncmp( ct, "text/plain", 10 ) != 0 ) 827 { 729 730 ct = get_rfc822_header(msg, "Content-Type", msglen); 731 if (strncmp(ct, "text/plain", 10) != 0) { 828 732 /* Typing notification or something? */ 829 g_free( ct);733 g_free(ct); 830 734 return 1; 831 735 } 832 if( strcmp( cmd[2], "1" ) != 0 ) 833 handle = g_strdup_printf( "%s:%s", cmd[2], cmd[1] ); 834 else 835 handle = g_strdup( cmd[1] ); 836 837 imcb_buddy_msg( ic, handle, body, 0, 0 ); 838 g_free( handle ); 839 } 840 736 if (strcmp(cmd[2], "1") != 0) { 737 handle = g_strdup_printf("%s:%s", cmd[2], cmd[1]); 738 } else { 739 handle = g_strdup(cmd[1]); 740 } 741 742 imcb_buddy_msg(ic, handle, body, 0, 0); 743 g_free(handle); 744 } 745 841 746 return 1; 842 747 } 843 748 844 void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error)749 void msn_auth_got_passport_token(struct im_connection *ic, const char *token, const char *error) 845 750 { 846 751 struct msn_data *md; 847 752 848 753 /* Dead connection? */ 849 if ( g_slist_find( msn_connections, ic ) == NULL )754 if (g_slist_find(msn_connections, ic) == NULL) { 850 755 return; 851 756 } 757 852 758 md = ic->proto_data; 853 854 if( token ) 855 { 856 msn_ns_write( ic, -1, "USR %d SSO S %s %s {%s}\r\n", ++md->trId, md->tokens[0], token, md->uuid ); 857 } 858 else 859 { 860 imcb_error( ic, "Error during Passport authentication: %s", error ); 861 imc_logout( ic, TRUE ); 862 } 863 } 864 865 void msn_auth_got_contact_list( struct im_connection *ic ) 759 760 if (token) { 761 msn_ns_write(ic, -1, "USR %d SSO S %s %s {%s}\r\n", ++md->trId, md->tokens[0], token, md->uuid); 762 } else { 763 imcb_error(ic, "Error during Passport authentication: %s", error); 764 imc_logout(ic, TRUE); 765 } 766 } 767 768 void msn_auth_got_contact_list(struct im_connection *ic) 866 769 { 867 770 struct msn_data *md; 868 771 869 772 /* Dead connection? */ 870 if ( g_slist_find( msn_connections, ic ) == NULL )773 if (g_slist_find(msn_connections, ic) == NULL) { 871 774 return; 872 775 } 776 873 777 md = ic->proto_data; 874 msn_ns_write( ic, -1, "BLP %d %s\r\n", ++md->trId, "BL");875 } 876 877 static gboolean msn_ns_send_adl_1( gpointer key, gpointer value, gpointer data)778 msn_ns_write(ic, -1, "BLP %d %s\r\n", ++md->trId, "BL"); 779 } 780 781 static gboolean msn_ns_send_adl_1(gpointer key, gpointer value, gpointer data) 878 782 { 879 783 struct xt_node *adl = data, *d, *c; … … 884 788 char *domain; 885 789 char l[4]; 886 887 if ( ( bd->flags & 7 ) == 0 || ( bd->flags & MSN_BUDDY_ADL_SYNCED ) )790 791 if ((bd->flags & 7) == 0 || (bd->flags & MSN_BUDDY_ADL_SYNCED)) { 888 792 return FALSE; 889 890 strcpy( handle, bu->handle ); 891 if( ( domain = strchr( handle, '@' ) ) == NULL ) /* WTF */ 892 return FALSE; 793 } 794 795 strcpy(handle, bu->handle); 796 if ((domain = strchr(handle, '@')) == NULL) { /* WTF */ 797 return FALSE; 798 } 893 799 *domain = '\0'; 894 domain ++; 895 896 if( ( d = adl->children ) == NULL || 897 g_strcasecmp( xt_find_attr( d, "n" ), domain ) != 0 ) 898 { 899 d = xt_new_node( "d", NULL, NULL ); 900 xt_add_attr( d, "n", domain ); 901 xt_insert_child( adl, d ); 902 } 903 904 g_snprintf( l, sizeof( l ), "%d", bd->flags & 7 ); 905 c = xt_new_node( "c", NULL, NULL ); 906 xt_add_attr( c, "n", handle ); 907 xt_add_attr( c, "l", l ); 908 xt_add_attr( c, "t", "1" ); /* FIXME: Network type, i.e. 32 for Y!MSG */ 909 xt_insert_child( d, c ); 910 800 domain++; 801 802 if ((d = adl->children) == NULL || 803 g_strcasecmp(xt_find_attr(d, "n"), domain) != 0) { 804 d = xt_new_node("d", NULL, NULL); 805 xt_add_attr(d, "n", domain); 806 xt_insert_child(adl, d); 807 } 808 809 g_snprintf(l, sizeof(l), "%d", bd->flags & 7); 810 c = xt_new_node("c", NULL, NULL); 811 xt_add_attr(c, "n", handle); 812 xt_add_attr(c, "l", l); 813 xt_add_attr(c, "t", "1"); /* FIXME: Network type, i.e. 32 for Y!MSG */ 814 xt_insert_child(d, c); 815 911 816 /* Do this in batches of 100. */ 912 817 bd->flags |= MSN_BUDDY_ADL_SYNCED; … … 914 819 } 915 820 916 static void msn_ns_send_adl( struct im_connection *ic)821 static void msn_ns_send_adl(struct im_connection *ic) 917 822 { 918 823 struct xt_node *adl; 919 824 struct msn_data *md = ic->proto_data; 920 825 char *adls; 921 922 adl = xt_new_node( "ml", NULL, NULL ); 923 xt_add_attr( adl, "l", "1" ); 924 g_tree_foreach( md->domaintree, msn_ns_send_adl_1, adl ); 925 if( adl->children == NULL ) 926 { 826 827 adl = xt_new_node("ml", NULL, NULL); 828 xt_add_attr(adl, "l", "1"); 829 g_tree_foreach(md->domaintree, msn_ns_send_adl_1, adl); 830 if (adl->children == NULL) { 927 831 /* This tells the caller that we're done now. */ 928 832 md->adl_todo = -1; 929 xt_free_node( adl);833 xt_free_node(adl); 930 834 return; 931 835 } 932 933 adls = xt_to_string( adl);934 xt_free_node( adl);935 msn_ns_write( ic, -1, "ADL %d %zd\r\n%s", ++md->trId, strlen( adls ), adls);936 g_free( adls);937 } 938 939 static void msn_ns_send_adl_start( struct im_connection *ic)836 837 adls = xt_to_string(adl); 838 xt_free_node(adl); 839 msn_ns_write(ic, -1, "ADL %d %zd\r\n%s", ++md->trId, strlen(adls), adls); 840 g_free(adls); 841 } 842 843 static void msn_ns_send_adl_start(struct im_connection *ic) 940 844 { 941 845 struct msn_data *md; 942 846 GSList *l; 943 847 944 848 /* Dead connection? */ 945 if ( g_slist_find( msn_connections, ic ) == NULL )849 if (g_slist_find(msn_connections, ic) == NULL) { 946 850 return; 947 851 } 852 948 853 md = ic->proto_data; 949 854 md->adl_todo = 0; 950 for( l = ic->bee->users; l; l = l->next ) 951 { 855 for (l = ic->bee->users; l; l = l->next) { 952 856 bee_user_t *bu = l->data; 953 857 struct msn_buddy_data *bd = bu->data; 954 955 if ( bu->ic != ic || ( bd->flags & 7 ) == 0 )858 859 if (bu->ic != ic || (bd->flags & 7) == 0) { 956 860 continue; 957 861 } 862 958 863 bd->flags &= ~MSN_BUDDY_ADL_SYNCED; 959 864 md->adl_todo++; 960 865 } 961 962 msn_ns_send_adl( ic);963 } 964 965 int msn_ns_finish_login( struct im_connection *ic)866 867 msn_ns_send_adl(ic); 868 } 869 870 int msn_ns_finish_login(struct im_connection *ic) 966 871 { 967 872 struct msn_data *md = ic->proto_data; 968 969 if ( ic->flags & OPT_LOGGED_IN )873 874 if (ic->flags & OPT_LOGGED_IN) { 970 875 return 1; 971 972 if( md->adl_todo < 0 ) 876 } 877 878 if (md->adl_todo < 0) { 973 879 md->flags |= MSN_DONE_ADL; 974 975 if( ( md->flags & MSN_DONE_ADL ) && ( md->flags & MSN_GOT_PROFILE ) ) 976 { 977 if( md->flags & MSN_EMAIL_UNVERIFIED ) 978 imcb_connected( ic ); 979 else 980 return msn_ns_set_display_name( ic, set_getstr( &ic->acc->set, "display_name" ) ); 981 } 982 880 } 881 882 if ((md->flags & MSN_DONE_ADL) && (md->flags & MSN_GOT_PROFILE)) { 883 if (md->flags & MSN_EMAIL_UNVERIFIED) { 884 imcb_connected(ic); 885 } else { 886 return msn_ns_set_display_name(ic, set_getstr(&ic->acc->set, "display_name")); 887 } 888 } 889 983 890 return 1; 984 891 } 985 892 986 int msn_ns_sendmessage( struct im_connection *ic, bee_user_t *bu, const char *text)893 int msn_ns_sendmessage(struct im_connection *ic, bee_user_t *bu, const char *text) 987 894 { 988 895 struct msn_data *md = ic->proto_data; 989 896 int type = 0; 990 897 char *buf, *handle; 991 992 if ( strncmp( text, "\r\r\r", 3 ) == 0 )898 899 if (strncmp(text, "\r\r\r", 3) == 0) { 993 900 /* Err. Shouldn't happen but I guess it can. Don't send others 994 901 any of the "SHAKE THAT THING" messages. :-D */ 995 902 return 1; 996 903 } 904 997 905 /* This might be a federated contact. Get its network number, 998 906 prefixed to bu->handle with a colon. Default is 1. */ 999 for ( handle = bu->handle; g_ascii_isdigit( *handle ); handle ++ )907 for (handle = bu->handle; g_ascii_isdigit(*handle); handle++) { 1000 908 type = type * 10 + *handle - '0'; 1001 if( *handle == ':' ) 1002 handle ++; 1003 else 909 } 910 if (*handle == ':') { 911 handle++; 912 } else { 1004 913 type = 1; 1005 1006 buf = g_strdup_printf( "%s%s", MSN_MESSAGE_HEADERS, text ); 1007 1008 if( msn_ns_write( ic, -1, "UUM %d %s %d %d %zd\r\n%s", 1009 ++md->trId, handle, type, 1010 1, /* type == IM (not nudge/typing) */ 1011 strlen( buf ), buf ) ) 914 } 915 916 buf = g_strdup_printf("%s%s", MSN_MESSAGE_HEADERS, text); 917 918 if (msn_ns_write(ic, -1, "UUM %d %s %d %d %zd\r\n%s", 919 ++md->trId, handle, type, 920 1, /* type == IM (not nudge/typing) */ 921 strlen(buf), buf)) { 1012 922 return 1; 1013 else923 } else { 1014 924 return 0; 1015 } 1016 1017 void msn_ns_oim_send_queue( struct im_connection *ic, GSList **msgq ) 925 } 926 } 927 928 void msn_ns_oim_send_queue(struct im_connection *ic, GSList **msgq) 1018 929 { 1019 930 GSList *l; 1020 1021 for( l = *msgq; l; l = l->next ) 1022 { 931 932 for (l = *msgq; l; l = l->next) { 1023 933 struct msn_message *m = l->data; 1024 bee_user_t *bu = bee_user_by_handle( ic->bee, ic, m->who);1025 1026 if ( bu )1027 if ( !msn_ns_sendmessage( ic, bu, m->text ) )934 bee_user_t *bu = bee_user_by_handle(ic->bee, ic, m->who); 935 936 if (bu) { 937 if (!msn_ns_sendmessage(ic, bu, m->text)) { 1028 938 return; 1029 } 1030 1031 while( *msgq != NULL ) 1032 { 939 } 940 } 941 } 942 943 while (*msgq != NULL) { 1033 944 struct msn_message *m = (*msgq)->data; 1034 1035 g_free( m->who);1036 g_free( m->text);1037 g_free( m);1038 1039 *msgq = g_slist_remove( *msgq, m);1040 } 1041 } 945 946 g_free(m->who); 947 g_free(m->text); 948 g_free(m); 949 950 *msgq = g_slist_remove(*msgq, m); 951 } 952 } -
protocols/msn/sb.c
raf359b4 r5ebff60 1 1 /********************************************************************\ 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * … … 31 31 #include "invitation.h" 32 32 33 static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond);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, ...)33 static gboolean msn_sb_callback(gpointer data, gint source, b_input_condition cond); 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 38 { 39 39 va_list params; … … 41 41 size_t len; 42 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\n", 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);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\n", sb->fd, out); 50 } 51 52 len = strlen(out); 53 st = write(sb->fd, out, len); 54 g_free(out); 55 if (st != len) { 56 msn_sb_destroy(sb); 57 57 return 0; 58 58 } 59 59 60 60 return 1; 61 61 } 62 62 63 int msn_sb_write_msg( struct im_connection *ic, struct msn_message *m)63 int msn_sb_write_msg(struct im_connection *ic, struct msn_message *m) 64 64 { 65 65 struct msn_data *md = ic->proto_data; … … 67 67 68 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 { 69 if ((sb = msn_sb_spare(ic))) { 70 debug("Trying to use a spare switchboard to message %s", m->who); 71 72 sb->who = g_strdup(m->who); 73 if (msn_sb_write(sb, "CAL %d %s\r\n", ++sb->trId, m->who)) { 76 74 /* 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 75 sb->msgq = g_slist_append(sb->msgq, m); 76 return(1); 77 } 78 } 79 80 debug("Creating a new switchboard to message %s", m->who); 81 84 82 /* 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 83 if (!msn_ns_write(ic, -1, "XFR %d SB\r\n", ++md->trId)) { 84 g_free(m->who); 85 g_free(m->text); 86 g_free(m); 87 88 return(0); 89 } 90 94 91 /* 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 92 md->msgq = g_slist_append(md->msgq, m); 93 97 94 /* FIXME: If the switchboard creation fails, the message will not be sent. */ 98 99 return( 1);100 } 101 102 struct msn_switchboard *msn_sb_create( struct im_connection *ic, char *host, int port, char *key, int session)95 96 return(1); 97 } 98 99 struct msn_switchboard *msn_sb_create(struct im_connection *ic, char *host, int port, char *key, int session) 103 100 { 104 101 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 102 struct msn_switchboard *sb = g_new0(struct msn_switchboard, 1); 103 104 sb->fd = proxy_connect(host, port, msn_sb_connected, sb); 105 if (sb->fd < 0) { 106 g_free(sb); 107 return(NULL); 108 } 109 114 110 sb->ic = ic; 115 sb->key = g_strdup( key);111 sb->key = g_strdup(key); 116 112 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 124 struct msn_switchboard *msn_sb_by_handle( struct im_connection *ic, const char *handle)113 114 msn_switchboards = g_slist_append(msn_switchboards, sb); 115 md->switchboards = g_slist_append(md->switchboards, sb); 116 117 return(sb); 118 } 119 120 struct msn_switchboard *msn_sb_by_handle(struct im_connection *ic, const char *handle) 125 121 { 126 122 struct msn_data *md = ic->proto_data; 127 123 struct msn_switchboard *sb; 128 124 GSList *l; 129 130 for( l = md->switchboards; l; l = l->next ) 131 { 125 126 for (l = md->switchboards; l; l = l->next) { 132 127 sb = l->data; 133 if( sb->who && strcmp( sb->who, handle ) == 0 ) 134 return( sb ); 135 } 136 137 return( NULL ); 138 } 139 140 struct msn_switchboard *msn_sb_by_chat( struct groupchat *c ) 128 if (sb->who && strcmp(sb->who, handle) == 0) { 129 return(sb); 130 } 131 } 132 133 return(NULL); 134 } 135 136 struct msn_switchboard *msn_sb_by_chat(struct groupchat *c) 141 137 { 142 138 struct msn_data *md = c->ic->proto_data; 143 139 struct msn_switchboard *sb; 144 140 GSList *l; 145 146 for( l = md->switchboards; l; l = l->next ) 147 { 141 142 for (l = md->switchboards; l; l = l->next) { 148 143 sb = l->data; 149 if( sb->chat == c ) 150 return( sb ); 151 } 152 153 return( NULL ); 154 } 155 156 struct msn_switchboard *msn_sb_spare( struct im_connection *ic ) 144 if (sb->chat == c) { 145 return(sb); 146 } 147 } 148 149 return(NULL); 150 } 151 152 struct msn_switchboard *msn_sb_spare(struct im_connection *ic) 157 153 { 158 154 struct msn_data *md = ic->proto_data; 159 155 struct msn_switchboard *sb; 160 156 GSList *l; 161 162 for( l = md->switchboards; l; l = l->next ) 163 { 157 158 for (l = md->switchboards; l; l = l->next) { 164 159 sb = l->data; 165 if ( !sb->who && !sb->chat )166 return( sb);167 }168 169 return( NULL ); 170 } 171 172 int msn_sb_sendmessage( struct msn_switchboard *sb, char *text ) 173 { 174 if( sb->ready ) 175 {160 if (!sb->who && !sb->chat) { 161 return(sb); 162 } 163 } 164 165 return(NULL); 166 } 167 168 int msn_sb_sendmessage(struct msn_switchboard *sb, char *text) 169 { 170 if (sb->ready) { 176 171 char *buf; 177 172 int i, j; 178 173 179 174 /* 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, NUDGE_MESSAGE ) == 0 ) 187 { 188 buf = g_strdup( MSN_NUDGE_HEADERS ); 189 i = strlen( buf ); 190 } 191 else if( strcmp( text, SB_KEEPALIVE_MESSAGE ) == 0 ) 192 { 193 buf = g_strdup( MSN_SB_KEEPALIVE_HEADERS ); 194 i = strlen( buf ); 195 } 196 else if( strncmp( text, MSN_INVITE_HEADERS, sizeof( MSN_INVITE_HEADERS ) - 1 ) == 0 ) 197 { 198 buf = g_strdup( text ); 199 i = strlen( buf ); 200 } 201 else 202 { 203 buf = g_new0( char, sizeof( MSN_MESSAGE_HEADERS ) + strlen( text ) * 2 + 1 ); 204 i = strlen( MSN_MESSAGE_HEADERS ); 205 206 strcpy( buf, MSN_MESSAGE_HEADERS ); 207 for( j = 0; text[j]; j ++ ) 208 { 209 if( text[j] == '\n' ) 175 if (strcmp(text, TYPING_NOTIFICATION_MESSAGE) == 0) { 176 i = strlen(MSN_TYPING_HEADERS) + strlen(sb->ic->acc->user); 177 buf = g_new0(char, i); 178 i = g_snprintf(buf, i, MSN_TYPING_HEADERS, sb->ic->acc->user); 179 } else if (strcmp(text, NUDGE_MESSAGE) == 0) { 180 buf = g_strdup(MSN_NUDGE_HEADERS); 181 i = strlen(buf); 182 } else if (strcmp(text, SB_KEEPALIVE_MESSAGE) == 0) { 183 buf = g_strdup(MSN_SB_KEEPALIVE_HEADERS); 184 i = strlen(buf); 185 } else if (strncmp(text, MSN_INVITE_HEADERS, sizeof(MSN_INVITE_HEADERS) - 1) == 0) { 186 buf = g_strdup(text); 187 i = strlen(buf); 188 } else { 189 buf = g_new0(char, sizeof(MSN_MESSAGE_HEADERS) + strlen(text) * 2 + 1); 190 i = strlen(MSN_MESSAGE_HEADERS); 191 192 strcpy(buf, MSN_MESSAGE_HEADERS); 193 for (j = 0; text[j]; j++) { 194 if (text[j] == '\n') { 210 195 buf[i++] = '\r'; 211 196 } 197 212 198 buf[i++] = text[j]; 213 199 } 214 200 } 215 201 216 202 /* Build the final packet (MSG command + the message). */ 217 if( msn_sb_write( sb, "MSG %d N %d\r\n%s", ++sb->trId, i, buf ) ) 218 { 219 g_free( buf ); 203 if (msn_sb_write(sb, "MSG %d N %d\r\n%s", ++sb->trId, i, buf)) { 204 g_free(buf); 220 205 return 1; 221 } 222 else 223 { 224 g_free( buf ); 206 } else { 207 g_free(buf); 225 208 return 0; 226 209 } 227 } 228 else if( sb->who ) 229 { 230 struct msn_message *m = g_new0( struct msn_message, 1 ); 231 232 m->who = g_strdup( "" ); 233 m->text = g_strdup( text ); 234 sb->msgq = g_slist_append( sb->msgq, m ); 235 236 return( 1 ); 237 } 238 else 239 { 240 return( 0 ); 241 } 242 } 243 244 struct groupchat *msn_sb_to_chat( struct msn_switchboard *sb ) 210 } else if (sb->who) { 211 struct msn_message *m = g_new0(struct msn_message, 1); 212 213 m->who = g_strdup(""); 214 m->text = g_strdup(text); 215 sb->msgq = g_slist_append(sb->msgq, m); 216 217 return(1); 218 } else { 219 return(0); 220 } 221 } 222 223 struct groupchat *msn_sb_to_chat(struct msn_switchboard *sb) 245 224 { 246 225 struct im_connection *ic = sb->ic; 247 226 struct groupchat *c = NULL; 248 227 char buf[1024]; 249 228 250 229 /* Create the groupchat structure. */ 251 g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session ); 252 if( sb->who ) 253 c = bee_chat_by_title( ic->bee, ic, sb->who ); 254 if( c && !msn_sb_by_chat( c ) ) 230 g_snprintf(buf, sizeof(buf), "MSN groupchat session %d", sb->session); 231 if (sb->who) { 232 c = bee_chat_by_title(ic->bee, ic, sb->who); 233 } 234 if (c && !msn_sb_by_chat(c)) { 255 235 sb->chat = c; 256 else 257 sb->chat = imcb_chat_new( ic, buf ); 258 236 } else { 237 sb->chat = imcb_chat_new(ic, buf); 238 } 239 259 240 /* Populate the channel. */ 260 if( sb->who ) imcb_chat_add_buddy( sb->chat, sb->who ); 261 imcb_chat_add_buddy( sb->chat, ic->acc->user ); 262 241 if (sb->who) { 242 imcb_chat_add_buddy(sb->chat, sb->who); 243 } 244 imcb_chat_add_buddy(sb->chat, ic->acc->user); 245 263 246 /* And make sure the switchboard doesn't look like a regular chat anymore. */ 264 if( sb->who ) 265 { 266 g_free( sb->who ); 247 if (sb->who) { 248 g_free(sb->who); 267 249 sb->who = NULL; 268 250 } 269 251 270 252 return sb->chat; 271 253 } 272 254 273 void msn_sb_destroy( struct msn_switchboard *sb)255 void msn_sb_destroy(struct msn_switchboard *sb) 274 256 { 275 257 struct im_connection *ic = sb->ic; 276 258 struct msn_data *md = ic->proto_data; 277 278 debug( "Destroying switchboard: %s", sb->who ? sb->who : sb->key ? sb->key : "" ); 279 280 msn_msgq_purge( ic, &sb->msgq ); 281 msn_sb_stop_keepalives( sb ); 282 283 if( sb->key ) g_free( sb->key ); 284 if( sb->who ) g_free( sb->who ); 285 286 if( sb->chat ) 287 { 288 imcb_chat_free( sb->chat ); 289 } 290 291 if( sb->handler ) 292 { 293 if( sb->handler->rxq ) g_free( sb->handler->rxq ); 294 if( sb->handler->cmd_text ) g_free( sb->handler->cmd_text ); 295 g_free( sb->handler ); 296 } 297 298 if( sb->inp ) b_event_remove( sb->inp ); 299 closesocket( sb->fd ); 300 301 msn_switchboards = g_slist_remove( msn_switchboards, sb ); 302 md->switchboards = g_slist_remove( md->switchboards, sb ); 303 g_free( sb ); 304 } 305 306 gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond ) 259 260 debug("Destroying switchboard: %s", sb->who ? sb->who : sb->key ? sb->key : ""); 261 262 msn_msgq_purge(ic, &sb->msgq); 263 msn_sb_stop_keepalives(sb); 264 265 if (sb->key) { 266 g_free(sb->key); 267 } 268 if (sb->who) { 269 g_free(sb->who); 270 } 271 272 if (sb->chat) { 273 imcb_chat_free(sb->chat); 274 } 275 276 if (sb->handler) { 277 if (sb->handler->rxq) { 278 g_free(sb->handler->rxq); 279 } 280 if (sb->handler->cmd_text) { 281 g_free(sb->handler->cmd_text); 282 } 283 g_free(sb->handler); 284 } 285 286 if (sb->inp) { 287 b_event_remove(sb->inp); 288 } 289 closesocket(sb->fd); 290 291 msn_switchboards = g_slist_remove(msn_switchboards, sb); 292 md->switchboards = g_slist_remove(md->switchboards, sb); 293 g_free(sb); 294 } 295 296 gboolean msn_sb_connected(gpointer data, gint source, b_input_condition cond) 307 297 { 308 298 struct msn_switchboard *sb = data; … … 310 300 struct msn_data *md; 311 301 char buf[1024]; 312 302 313 303 /* Are we still alive? */ 314 if ( !g_slist_find( msn_switchboards, sb ) )304 if (!g_slist_find(msn_switchboards, sb)) { 315 305 return FALSE; 316 306 } 307 317 308 ic = sb->ic; 318 309 md = ic->proto_data; 319 320 if( source != sb->fd ) 321 { 322 debug( "Error %d while connecting to switchboard server", 1 ); 323 msn_sb_destroy( sb ); 310 311 if (source != sb->fd) { 312 debug("Error %d while connecting to switchboard server", 1); 313 msn_sb_destroy(sb); 324 314 return FALSE; 325 315 } 326 316 327 317 /* Prepare the callback */ 328 sb->handler = g_new0( struct msn_handler_data, 1);318 sb->handler = g_new0(struct msn_handler_data, 1); 329 319 sb->handler->fd = sb->fd; 330 sb->handler->rxq = g_new0( char, 1);320 sb->handler->rxq = g_new0(char, 1); 331 321 sb->handler->data = sb; 332 322 sb->handler->exec_command = msn_sb_command; 333 323 sb->handler->exec_message = msn_sb_message; 334 335 if( sb->session == MSN_SB_NEW ) 336 g_snprintf( buf, sizeof( buf ), "USR %d %s;{%s} %s\r\n", ++sb->trId, ic->acc->user, md->uuid, sb->key ); 337 else 338 g_snprintf( buf, sizeof( buf ), "ANS %d %s;{%s} %s %d\r\n", ++sb->trId, ic->acc->user, md->uuid, sb->key, sb->session ); 339 340 if( msn_sb_write( sb, "%s", buf ) ) 341 sb->inp = b_input_add( sb->fd, B_EV_IO_READ, msn_sb_callback, sb ); 342 else 343 debug( "Error %d while connecting to switchboard server", 2 ); 344 324 325 if (sb->session == MSN_SB_NEW) { 326 g_snprintf(buf, sizeof(buf), "USR %d %s;{%s} %s\r\n", ++sb->trId, ic->acc->user, md->uuid, sb->key); 327 } else { 328 g_snprintf(buf, sizeof(buf), "ANS %d %s;{%s} %s %d\r\n", ++sb->trId, ic->acc->user, md->uuid, sb->key, 329 sb->session); 330 } 331 332 if (msn_sb_write(sb, "%s", buf)) { 333 sb->inp = b_input_add(sb->fd, B_EV_IO_READ, msn_sb_callback, sb); 334 } else { 335 debug("Error %d while connecting to switchboard server", 2); 336 } 337 345 338 return FALSE; 346 339 } 347 340 348 static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond)341 static gboolean msn_sb_callback(gpointer data, gint source, b_input_condition cond) 349 342 { 350 343 struct msn_switchboard *sb = data; 351 344 struct im_connection *ic = sb->ic; 352 345 struct msn_data *md = ic->proto_data; 353 354 if ( msn_handler( sb->handler ) != -1 )346 347 if (msn_handler(sb->handler) != -1) { 355 348 return TRUE; 356 357 if( sb->msgq != NULL ) 358 { 359 time_t now = time( NULL ); 360 361 if( now - md->first_sb_failure > 600 ) 362 { 349 } 350 351 if (sb->msgq != NULL) { 352 time_t now = time(NULL); 353 354 if (now - md->first_sb_failure > 600) { 363 355 /* It's not really the first one, but the start of this "series". 364 356 With this, the warning below will be shown only if this happens … … 368 360 md->sb_failures = 0; 369 361 } 370 371 debug( "Error: Switchboard died");372 if ( ++ md->sb_failures >= 3 )373 imcb_log( 374 "There might be problems delivering your messages.");375 376 if( md->msgq == NULL ) 377 {362 363 debug("Error: Switchboard died"); 364 if (++md->sb_failures >= 3) { 365 imcb_log(ic, "Warning: Many switchboard failures on MSN connection. " 366 "There might be problems delivering your messages."); 367 } 368 369 if (md->msgq == NULL) { 378 370 md->msgq = sb->msgq; 379 } 380 else 381 { 371 } else { 382 372 GSList *l; 383 384 for( l = md->msgq; l->next; l = l->next ); 373 374 for (l = md->msgq; l->next; l = l->next) { 375 ; 376 } 385 377 l->next = sb->msgq; 386 378 } 387 379 sb->msgq = NULL; 388 389 debug( 390 "creating a new switchboard to retry.");391 if ( !msn_ns_write( ic, -1, "XFR %d SB\r\n", ++md->trId ) )380 381 debug("Moved queued messages back to the main queue, " 382 "creating a new switchboard to retry."); 383 if (!msn_ns_write(ic, -1, "XFR %d SB\r\n", ++md->trId)) { 392 384 return FALSE; 393 } 394 395 msn_sb_destroy( sb ); 385 } 386 } 387 388 msn_sb_destroy(sb); 396 389 return FALSE; 397 390 } 398 391 399 static int msn_sb_command( struct msn_handler_data *handler, char **cmd, int num_parts)392 static int msn_sb_command(struct msn_handler_data *handler, char **cmd, int num_parts) 400 393 { 401 394 struct msn_switchboard *sb = handler->data; 402 395 struct im_connection *ic = sb->ic; 403 404 if( !num_parts ) 405 { 396 397 if (!num_parts) { 406 398 /* Hrrm... Empty command...? Ignore? */ 407 return( 1 ); 408 } 409 410 if( strcmp( cmd[0], "XFR" ) == 0 ) 411 { 412 imcb_error( ic, "Received an XFR from a switchboard server, unable to comply! This is likely to be a bug, please report it!" ); 413 imc_logout( ic, TRUE ); 414 return( 0 ); 415 } 416 else if( strcmp( cmd[0], "USR" ) == 0 ) 417 { 418 if( num_parts < 5 ) 419 { 420 msn_sb_destroy( sb ); 421 return( 0 ); 422 } 423 424 if( strcmp( cmd[2], "OK" ) != 0 ) 425 { 426 msn_sb_destroy( sb ); 427 return( 0 ); 428 } 429 430 if( sb->who ) 431 return msn_sb_write( sb, "CAL %d %s\r\n", ++sb->trId, sb->who ); 432 else 433 debug( "Just created a switchboard, but I don't know what to do with it." ); 434 } 435 else if( strcmp( cmd[0], "IRO" ) == 0 ) 436 { 399 return(1); 400 } 401 402 if (strcmp(cmd[0], "XFR") == 0) { 403 imcb_error(ic, 404 "Received an XFR from a switchboard server, unable to comply! This is likely to be a bug, please report it!"); 405 imc_logout(ic, TRUE); 406 return(0); 407 } else if (strcmp(cmd[0], "USR") == 0) { 408 if (num_parts < 5) { 409 msn_sb_destroy(sb); 410 return(0); 411 } 412 413 if (strcmp(cmd[2], "OK") != 0) { 414 msn_sb_destroy(sb); 415 return(0); 416 } 417 418 if (sb->who) { 419 return msn_sb_write(sb, "CAL %d %s\r\n", ++sb->trId, sb->who); 420 } else { 421 debug("Just created a switchboard, but I don't know what to do with it."); 422 } 423 } else if (strcmp(cmd[0], "IRO") == 0) { 437 424 int num, tot; 438 439 if( num_parts < 6 ) 440 { 441 msn_sb_destroy( sb ); 442 return( 0 ); 443 } 444 445 num = atoi( cmd[2] ); 446 tot = atoi( cmd[3] ); 447 448 if( tot <= 0 ) 449 { 450 msn_sb_destroy( sb ); 451 return( 0 ); 452 } 453 else if( tot > 1 ) 454 { 425 426 if (num_parts < 6) { 427 msn_sb_destroy(sb); 428 return(0); 429 } 430 431 num = atoi(cmd[2]); 432 tot = atoi(cmd[3]); 433 434 if (tot <= 0) { 435 msn_sb_destroy(sb); 436 return(0); 437 } else if (tot > 1) { 455 438 char buf[1024]; 456 439 457 440 /* For as much as I understand this MPOP stuff now, a 458 441 switchboard has two (or more) roster entries per 459 442 participant. One "bare JID" and one JID;UUID. Ignore 460 443 the latter. */ 461 if( !strchr( cmd[4], ';' ) ) 462 { 444 if (!strchr(cmd[4], ';')) { 463 445 /* HACK: Since even 1:1 chats now have >2 participants 464 446 (ourselves included) it gets hard to tell them apart 465 447 from rooms. Let's hope this is enough: */ 466 if( sb->chat == NULL && num != tot ) 467 { 468 g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session ); 469 sb->chat = imcb_chat_new( ic, buf ); 470 471 g_free( sb->who ); 448 if (sb->chat == NULL && num != tot) { 449 g_snprintf(buf, sizeof(buf), "MSN groupchat session %d", sb->session); 450 sb->chat = imcb_chat_new(ic, buf); 451 452 g_free(sb->who); 472 453 sb->who = NULL; 473 454 } 474 475 if( sb->chat ) 476 imcb_chat_add_buddy( sb->chat, cmd[4] ); 477 } 478 455 456 if (sb->chat) { 457 imcb_chat_add_buddy(sb->chat, cmd[4]); 458 } 459 } 460 479 461 /* We have the full roster, start showing the channel to 480 462 the user. */ 481 if( num == tot && sb->chat ) 482 { 483 imcb_chat_add_buddy( sb->chat, ic->acc->user ); 484 } 485 } 486 } 487 else if( strcmp( cmd[0], "ANS" ) == 0 ) 488 { 489 if( num_parts < 3 ) 490 { 491 msn_sb_destroy( sb ); 492 return( 0 ); 493 } 494 495 if( strcmp( cmd[2], "OK" ) != 0 ) 496 { 497 debug( "Switchboard server sent a negative ANS reply" ); 498 msn_sb_destroy( sb ); 499 return( 0 ); 500 } 501 463 if (num == tot && sb->chat) { 464 imcb_chat_add_buddy(sb->chat, ic->acc->user); 465 } 466 } 467 } else if (strcmp(cmd[0], "ANS") == 0) { 468 if (num_parts < 3) { 469 msn_sb_destroy(sb); 470 return(0); 471 } 472 473 if (strcmp(cmd[2], "OK") != 0) { 474 debug("Switchboard server sent a negative ANS reply"); 475 msn_sb_destroy(sb); 476 return(0); 477 } 478 502 479 sb->ready = 1; 503 504 msn_sb_start_keepalives( sb, FALSE ); 505 } 506 else if( strcmp( cmd[0], "CAL" ) == 0 ) 507 { 508 if( num_parts < 4 || !g_ascii_isdigit( cmd[3][0] ) ) 509 { 510 msn_sb_destroy( sb ); 511 return( 0 ); 512 } 513 514 sb->session = atoi( cmd[3] ); 515 } 516 else if( strcmp( cmd[0], "JOI" ) == 0 ) 517 { 518 if( num_parts < 3 ) 519 { 520 msn_sb_destroy( sb ); 521 return( 0 ); 522 } 523 480 481 msn_sb_start_keepalives(sb, FALSE); 482 } else if (strcmp(cmd[0], "CAL") == 0) { 483 if (num_parts < 4 || !g_ascii_isdigit(cmd[3][0])) { 484 msn_sb_destroy(sb); 485 return(0); 486 } 487 488 sb->session = atoi(cmd[3]); 489 } else if (strcmp(cmd[0], "JOI") == 0) { 490 if (num_parts < 3) { 491 msn_sb_destroy(sb); 492 return(0); 493 } 494 524 495 /* See IRO above. Handle "bare JIDs" only. */ 525 if ( strchr( cmd[1], ';' ) )496 if (strchr(cmd[1], ';')) { 526 497 return 1; 527 528 if( sb->who && g_strcasecmp( cmd[1], sb->who ) == 0 ) 529 {498 } 499 500 if (sb->who && g_strcasecmp(cmd[1], sb->who) == 0) { 530 501 /* The user we wanted to talk to is finally there, let's send the queued messages then. */ 531 502 struct msn_message *m; 532 503 GSList *l; 533 504 int st = 1; 534 535 debug( "%s arrived in the switchboard session, now sending queued message(s)", cmd[1]);536 505 506 debug("%s arrived in the switchboard session, now sending queued message(s)", cmd[1]); 507 537 508 /* Without this, sendmessage() will put everything back on the queue... */ 538 509 sb->ready = 1; 539 540 while( ( l = sb->msgq ) ) 541 { 510 511 while ((l = sb->msgq)) { 542 512 m = l->data; 543 if( st ) 544 { 513 if (st) { 545 514 /* This hack is meant to convert a regular new chat into a groupchat */ 546 if( strcmp( m->text, GROUPCHAT_SWITCHBOARD_MESSAGE ) == 0 ) 547 msn_sb_to_chat( sb ); 548 else 549 st = msn_sb_sendmessage( sb, m->text ); 515 if (strcmp(m->text, GROUPCHAT_SWITCHBOARD_MESSAGE) == 0) { 516 msn_sb_to_chat(sb); 517 } else { 518 st = msn_sb_sendmessage(sb, m->text); 519 } 550 520 } 551 g_free( m->text ); 552 g_free( m->who ); 553 g_free( m ); 554 555 sb->msgq = g_slist_remove( sb->msgq, m ); 556 } 557 558 msn_sb_start_keepalives( sb, FALSE ); 559 560 return( st ); 561 } 562 else if( strcmp( cmd[1], ic->acc->user ) == 0 ) 563 { 521 g_free(m->text); 522 g_free(m->who); 523 g_free(m); 524 525 sb->msgq = g_slist_remove(sb->msgq, m); 526 } 527 528 msn_sb_start_keepalives(sb, FALSE); 529 530 return(st); 531 } else if (strcmp(cmd[1], ic->acc->user) == 0) { 564 532 /* Well, gee thanks. Thanks for letting me know I've arrived.. */ 565 } 566 else if( sb->who ) 567 { 568 debug( "Converting chat with %s to a groupchat because %s joined the session.", sb->who, cmd[1] ); 569 533 } else if (sb->who) { 534 debug("Converting chat with %s to a groupchat because %s joined the session.", sb->who, cmd[1]); 535 570 536 /* This SB is a one-to-one chat right now, but someone else is joining. */ 571 msn_sb_to_chat( sb ); 572 573 imcb_chat_add_buddy( sb->chat, cmd[1] ); 574 } 575 else if( sb->chat ) 576 { 577 imcb_chat_add_buddy( sb->chat, cmd[1] ); 537 msn_sb_to_chat(sb); 538 539 imcb_chat_add_buddy(sb->chat, cmd[1]); 540 } else if (sb->chat) { 541 imcb_chat_add_buddy(sb->chat, cmd[1]); 578 542 sb->ready = 1; 579 } 580 else 581 { 543 } else { 582 544 /* PANIC! */ 583 545 } 584 } 585 else if( strcmp( cmd[0], "MSG" ) == 0 ) 586 { 587 if( num_parts < 4 ) 588 { 589 msn_sb_destroy( sb ); 590 return( 0 ); 591 } 592 593 sb->handler->msglen = atoi( cmd[3] ); 594 595 if( sb->handler->msglen <= 0 ) 596 { 597 debug( "Received a corrupted message on the switchboard, the switchboard will be closed" ); 598 msn_sb_destroy( sb ); 599 return( 0 ); 600 } 601 } 602 else if( strcmp( cmd[0], "NAK" ) == 0 ) 603 { 604 if( sb->who ) 605 { 606 imcb_log( ic, "The MSN servers could not deliver one of your messages to %s.", sb->who ); 607 } 608 else 609 { 610 imcb_log( ic, "The MSN servers could not deliver one of your groupchat messages to all participants." ); 611 } 612 } 613 else if( strcmp( cmd[0], "BYE" ) == 0 ) 614 { 615 if( num_parts < 2 ) 616 { 617 msn_sb_destroy( sb ); 618 return( 0 ); 619 } 620 546 } else if (strcmp(cmd[0], "MSG") == 0) { 547 if (num_parts < 4) { 548 msn_sb_destroy(sb); 549 return(0); 550 } 551 552 sb->handler->msglen = atoi(cmd[3]); 553 554 if (sb->handler->msglen <= 0) { 555 debug("Received a corrupted message on the switchboard, the switchboard will be closed"); 556 msn_sb_destroy(sb); 557 return(0); 558 } 559 } else if (strcmp(cmd[0], "NAK") == 0) { 560 if (sb->who) { 561 imcb_log(ic, "The MSN servers could not deliver one of your messages to %s.", sb->who); 562 } else { 563 imcb_log(ic, 564 "The MSN servers could not deliver one of your groupchat messages to all participants."); 565 } 566 } else if (strcmp(cmd[0], "BYE") == 0) { 567 if (num_parts < 2) { 568 msn_sb_destroy(sb); 569 return(0); 570 } 571 621 572 /* if( cmd[2] && *cmd[2] == '1' ) -=> Chat is being cleaned up because of idleness */ 622 623 if( sb->who ) 624 { 625 msn_sb_stop_keepalives( sb ); 626 573 574 if (sb->who) { 575 msn_sb_stop_keepalives(sb); 576 627 577 /* This is a single-person chat, and the other person is leaving. */ 628 g_free( sb->who);578 g_free(sb->who); 629 579 sb->who = NULL; 630 580 sb->ready = 0; 631 632 debug( "Person %s left the one-to-one switchboard connection. Keeping it around as a spare...", cmd[1] ); 633 581 582 debug("Person %s left the one-to-one switchboard connection. Keeping it around as a spare...", 583 cmd[1]); 584 634 585 /* We could clean up the switchboard now, but keeping it around 635 586 as a spare for a next conversation sounds more sane to me. 636 587 The server will clean it up when it's idle for too long. */ 637 } 638 else if( sb->chat && !strchr( cmd[1], ';' ) ) 639 { 640 imcb_chat_remove_buddy( sb->chat, cmd[1], "" ); 641 } 642 else 643 { 588 } else if (sb->chat && !strchr(cmd[1], ';')) { 589 imcb_chat_remove_buddy(sb->chat, cmd[1], ""); 590 } else { 644 591 /* PANIC! */ 645 592 } 646 } 647 else if( g_ascii_isdigit( cmd[0][0] ) ) 648 { 649 int num = atoi( cmd[0] ); 650 const struct msn_status_code *err = msn_status_by_number( num ); 651 593 } else if (g_ascii_isdigit(cmd[0][0])) { 594 int num = atoi(cmd[0]); 595 const struct msn_status_code *err = msn_status_by_number(num); 596 652 597 /* If the person is offline, send an offline message instead, 653 598 and don't report an error. */ 654 if ( num == 217 )655 msn_ns_oim_send_queue( ic, &sb->msgq);656 else657 imcb_error( ic, "Error reported by switchboard server: %s", err->text);658 659 if( err->flags & STATUS_SB_FATAL ) 660 {661 msn_sb_destroy( sb);599 if (num == 217) { 600 msn_ns_oim_send_queue(ic, &sb->msgq); 601 } else { 602 imcb_error(ic, "Error reported by switchboard server: %s", err->text); 603 } 604 605 if (err->flags & STATUS_SB_FATAL) { 606 msn_sb_destroy(sb); 662 607 return 0; 663 } 664 else if( err->flags & STATUS_FATAL ) 665 { 666 imc_logout( ic, TRUE ); 608 } else if (err->flags & STATUS_FATAL) { 609 imc_logout(ic, TRUE); 667 610 return 0; 668 } 669 else if( err->flags & STATUS_SB_IM_SPARE ) 670 { 671 if( sb->who ) 672 { 611 } else if (err->flags & STATUS_SB_IM_SPARE) { 612 if (sb->who) { 673 613 /* Apparently some invitation failed. We might want to use this 674 614 board later, so keep it as a spare. */ 675 g_free( sb->who);615 g_free(sb->who); 676 616 sb->who = NULL; 677 617 678 618 /* Also clear the msgq, otherwise someone else might get them. */ 679 msn_msgq_purge( ic, &sb->msgq);680 } 681 619 msn_msgq_purge(ic, &sb->msgq); 620 } 621 682 622 /* Do NOT return 0 here, we want to keep this sb. */ 683 623 } 684 } 685 else 686 { 624 } else { 687 625 /* debug( "Received unknown command from switchboard server: %s", cmd[0] ); */ 688 626 } 689 690 return( 1);691 } 692 693 static int msn_sb_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts)627 628 return(1); 629 } 630 631 static int msn_sb_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts) 694 632 { 695 633 struct msn_switchboard *sb = handler->data; 696 634 struct im_connection *ic = sb->ic; 697 635 char *body; 698 699 if( !num_parts ) 700 return( 1 ); 701 702 if( ( body = strstr( msg, "\r\n\r\n" ) ) ) 636 637 if (!num_parts) { 638 return(1); 639 } 640 641 if ((body = strstr(msg, "\r\n\r\n"))) { 703 642 body += 4; 704 705 if( strcmp( cmd[0], "MSG" ) == 0 ) 706 { 707 char *ct = get_rfc822_header( msg, "Content-Type:", msglen ); 708 709 if( !ct ) 710 return( 1 ); 711 712 if( g_strncasecmp( ct, "text/plain", 10 ) == 0 ) 713 { 714 g_free( ct ); 715 716 if( !body ) 717 return( 1 ); 718 719 if( sb->who ) 720 { 721 imcb_buddy_msg( ic, cmd[1], body, 0, 0 ); 722 } 723 else if( sb->chat ) 724 { 725 imcb_chat_msg( sb->chat, cmd[1], body, 0, 0 ); 726 } 727 else 728 { 643 } 644 645 if (strcmp(cmd[0], "MSG") == 0) { 646 char *ct = get_rfc822_header(msg, "Content-Type:", msglen); 647 648 if (!ct) { 649 return(1); 650 } 651 652 if (g_strncasecmp(ct, "text/plain", 10) == 0) { 653 g_free(ct); 654 655 if (!body) { 656 return(1); 657 } 658 659 if (sb->who) { 660 imcb_buddy_msg(ic, cmd[1], body, 0, 0); 661 } else if (sb->chat) { 662 imcb_chat_msg(sb->chat, cmd[1], body, 0, 0); 663 } else { 729 664 /* PANIC! */ 730 665 } … … 732 667 #if 0 733 668 // Disable MSN ft support for now. 734 else if( g_strncasecmp( ct, "text/x-msmsgsinvite", 19 ) == 0 ) 735 { 736 char *command = get_rfc822_header( body, "Invitation-Command:", blen ); 737 char *cookie = get_rfc822_header( body, "Invitation-Cookie:", blen ); 669 else if (g_strncasecmp(ct, "text/x-msmsgsinvite", 19) == 0) { 670 char *command = get_rfc822_header(body, "Invitation-Command:", blen); 671 char *cookie = get_rfc822_header(body, "Invitation-Cookie:", blen); 738 672 unsigned int icookie; 739 740 g_free( ct);741 673 674 g_free(ct); 675 742 676 /* Every invite should have both a Command and Cookie header */ 743 if ( !command || !cookie) {744 g_free( command);745 g_free( cookie);746 imcb_log( ic, "Warning: No command or cookie from %s", sb->who);677 if (!command || !cookie) { 678 g_free(command); 679 g_free(cookie); 680 imcb_log(ic, "Warning: No command or cookie from %s", sb->who); 747 681 return 1; 748 682 } 749 750 icookie = strtoul( cookie, NULL, 10);751 g_free( cookie);752 753 if ( g_strncasecmp( command, "INVITE", 6 ) == 0) {754 msn_invitation_invite( sb, cmd[1], icookie, body, blen);755 } else if ( g_strncasecmp( command, "ACCEPT", 6 ) == 0) {756 msn_invitation_accept( sb, cmd[1], icookie, body, blen);757 } else if ( g_strncasecmp( command, "CANCEL", 6 ) == 0) {758 msn_invitation_cancel( sb, cmd[1], icookie, body, blen);683 684 icookie = strtoul(cookie, NULL, 10); 685 g_free(cookie); 686 687 if (g_strncasecmp(command, "INVITE", 6) == 0) { 688 msn_invitation_invite(sb, cmd[1], icookie, body, blen); 689 } else if (g_strncasecmp(command, "ACCEPT", 6) == 0) { 690 msn_invitation_accept(sb, cmd[1], icookie, body, blen); 691 } else if (g_strncasecmp(command, "CANCEL", 6) == 0) { 692 msn_invitation_cancel(sb, cmd[1], icookie, body, blen); 759 693 } else { 760 imcb_log( 761 "command %s from %s", command, sb->who);762 } 763 764 g_free( command);694 imcb_log(ic, "Warning: Received invalid invitation with " 695 "command %s from %s", command, sb->who); 696 } 697 698 g_free(command); 765 699 } 766 700 #endif 767 else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 ) 768 { 701 else if (g_strncasecmp(ct, "application/x-msnmsgrp2p", 24) == 0) { 769 702 /* Not currently implemented. Don't warn about it since 770 703 this seems to be used for avatars now. */ 771 g_free( ct ); 772 } 773 else if( g_strncasecmp( ct, "text/x-msmsgscontrol", 20 ) == 0 ) 774 { 775 char *who = get_rfc822_header( msg, "TypingUser:", msglen ); 776 777 if( who ) 778 { 779 imcb_buddy_typing( ic, who, OPT_TYPING ); 780 g_free( who ); 781 } 782 783 g_free( ct ); 784 } 785 else 786 { 787 g_free( ct ); 788 } 789 } 790 791 return( 1 ); 792 } 793 794 static gboolean msn_sb_keepalive( gpointer data, gint source, b_input_condition cond ) 704 g_free(ct); 705 } else if (g_strncasecmp(ct, "text/x-msmsgscontrol", 20) == 0) { 706 char *who = get_rfc822_header(msg, "TypingUser:", msglen); 707 708 if (who) { 709 imcb_buddy_typing(ic, who, OPT_TYPING); 710 g_free(who); 711 } 712 713 g_free(ct); 714 } else { 715 g_free(ct); 716 } 717 } 718 719 return(1); 720 } 721 722 static gboolean msn_sb_keepalive(gpointer data, gint source, b_input_condition cond) 795 723 { 796 724 struct msn_switchboard *sb = data; 797 return sb->ready && msn_sb_sendmessage( sb, SB_KEEPALIVE_MESSAGE ); 798 } 799 800 void msn_sb_start_keepalives( struct msn_switchboard *sb, gboolean initial ) 725 726 return sb->ready && msn_sb_sendmessage(sb, SB_KEEPALIVE_MESSAGE); 727 } 728 729 void msn_sb_start_keepalives(struct msn_switchboard *sb, gboolean initial) 801 730 { 802 731 bee_user_t *bu; 803 804 if( sb && sb->who && sb->keepalive == 0 && 805 ( bu = bee_user_by_handle( sb->ic->bee, sb->ic, sb->who ) ) && 806 !( bu->flags & BEE_USER_ONLINE ) && 807 set_getbool( &sb->ic->acc->set, "switchboard_keepalives" ) ) 808 { 809 if( initial ) 810 msn_sb_keepalive( sb, 0, 0 ); 811 812 sb->keepalive = b_timeout_add( 20000, msn_sb_keepalive, sb ); 813 } 814 } 815 816 void msn_sb_stop_keepalives( struct msn_switchboard *sb ) 817 { 818 if( sb && sb->keepalive > 0 ) 819 { 820 b_event_remove( sb->keepalive ); 732 733 if (sb && sb->who && sb->keepalive == 0 && 734 (bu = bee_user_by_handle(sb->ic->bee, sb->ic, sb->who)) && 735 !(bu->flags & BEE_USER_ONLINE) && 736 set_getbool(&sb->ic->acc->set, "switchboard_keepalives")) { 737 if (initial) { 738 msn_sb_keepalive(sb, 0, 0); 739 } 740 741 sb->keepalive = b_timeout_add(20000, msn_sb_keepalive, sb); 742 } 743 } 744 745 void msn_sb_stop_keepalives(struct msn_switchboard *sb) 746 { 747 if (sb && sb->keepalive > 0) { 748 b_event_remove(sb->keepalive); 821 749 sb->keepalive = 0; 822 750 } -
protocols/msn/soap.c
raf359b4 r5ebff60 1 1 /********************************************************************\ 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * … … 44 44 received and parsed. See the various examples below. */ 45 45 46 typedef enum 47 { 46 typedef enum { 48 47 MSN_SOAP_OK, 49 48 MSN_SOAP_RETRY, … … 53 52 54 53 struct msn_soap_req_data; 55 typedef int (*msn_soap_func) ( struct msn_soap_req_data * ); 56 57 struct msn_soap_req_data 58 { 54 typedef int (*msn_soap_func) (struct msn_soap_req_data *); 55 56 struct msn_soap_req_data { 59 57 void *data; 60 58 struct im_connection *ic; 61 59 int ttl; 62 60 char *error; 63 61 64 62 char *url, *action, *payload; 65 63 struct http_request *http_req; 66 64 67 65 const struct xt_handler_entry *xml_parser; 68 66 msn_soap_func build_request, handle_response, free_data; 69 67 }; 70 68 71 static int msn_soap_send_request( struct msn_soap_req_data *req);72 static void msn_soap_free( struct msn_soap_req_data *soap_req);73 static void msn_soap_debug_print( const char *headers, const char *payload);74 75 static int msn_soap_start( 76 void *data,77 msn_soap_func build_request,78 const struct xt_handler_entry *xml_parser,79 msn_soap_func handle_response,80 msn_soap_func free_data)81 { 82 struct msn_soap_req_data *req = g_new0( struct msn_soap_req_data, 1);83 69 static int msn_soap_send_request(struct msn_soap_req_data *req); 70 static void msn_soap_free(struct msn_soap_req_data *soap_req); 71 static void msn_soap_debug_print(const char *headers, const char *payload); 72 73 static int msn_soap_start(struct im_connection *ic, 74 void *data, 75 msn_soap_func build_request, 76 const struct xt_handler_entry *xml_parser, 77 msn_soap_func handle_response, 78 msn_soap_func free_data) 79 { 80 struct msn_soap_req_data *req = g_new0(struct msn_soap_req_data, 1); 81 84 82 req->ic = ic; 85 83 req->data = data; … … 89 87 req->free_data = free_data; 90 88 req->ttl = 3; 91 92 return msn_soap_send_request( req);93 } 94 95 static void msn_soap_handle_response( struct http_request *http_req);96 97 static int msn_soap_send_request( struct msn_soap_req_data *soap_req)89 90 return msn_soap_send_request(req); 91 } 92 93 static void msn_soap_handle_response(struct http_request *http_req); 94 95 static int msn_soap_send_request(struct msn_soap_req_data *soap_req) 98 96 { 99 97 char *http_req; 100 98 char *soap_action = NULL; 101 99 url_t url; 102 103 soap_req->build_request( soap_req ); 104 105 if( soap_req->action ) 106 soap_action = g_strdup_printf( "SOAPAction: \"%s\"\r\n", soap_req->action ); 107 108 url_set( &url, soap_req->url ); 109 http_req = g_strdup_printf( SOAP_HTTP_REQUEST, url.file, url.host, 110 soap_action ? soap_action : "", 111 strlen( soap_req->payload ), soap_req->payload ); 112 113 msn_soap_debug_print( http_req, soap_req->payload ); 114 115 soap_req->http_req = http_dorequest( url.host, url.port, url.proto == PROTO_HTTPS, 116 http_req, msn_soap_handle_response, soap_req ); 117 118 g_free( http_req ); 119 g_free( soap_action ); 120 100 101 soap_req->build_request(soap_req); 102 103 if (soap_req->action) { 104 soap_action = g_strdup_printf("SOAPAction: \"%s\"\r\n", soap_req->action); 105 } 106 107 url_set(&url, soap_req->url); 108 http_req = g_strdup_printf(SOAP_HTTP_REQUEST, url.file, url.host, 109 soap_action ? soap_action : "", 110 strlen(soap_req->payload), soap_req->payload); 111 112 msn_soap_debug_print(http_req, soap_req->payload); 113 114 soap_req->http_req = http_dorequest(url.host, url.port, url.proto == PROTO_HTTPS, 115 http_req, msn_soap_handle_response, soap_req); 116 117 g_free(http_req); 118 g_free(soap_action); 119 121 120 return soap_req->http_req != NULL; 122 121 } 123 122 124 static void msn_soap_handle_response( struct http_request *http_req)123 static void msn_soap_handle_response(struct http_request *http_req) 125 124 { 126 125 struct msn_soap_req_data *soap_req = http_req->data; 127 126 int st; 128 129 if( g_slist_find( msn_connections, soap_req->ic ) == NULL ) 130 { 131 msn_soap_free( soap_req ); 127 128 if (g_slist_find(msn_connections, soap_req->ic) == NULL) { 129 msn_soap_free(soap_req); 132 130 return; 133 131 } 134 135 msn_soap_debug_print( http_req->reply_headers, http_req->reply_body ); 136 137 if( http_req->body_size > 0 ) 138 { 132 133 msn_soap_debug_print(http_req->reply_headers, http_req->reply_body); 134 135 if (http_req->body_size > 0) { 139 136 struct xt_parser *parser; 140 137 struct xt_node *err; 141 142 parser = xt_new( soap_req->xml_parser, soap_req ); 143 xt_feed( parser, http_req->reply_body, http_req->body_size ); 144 if( http_req->status_code == 500 && 145 ( err = xt_find_path( parser->root, "soap:Body/soap:Fault/detail/errorcode" ) ) && 146 err->text_len > 0 ) 147 { 148 if( strcmp( err->text, "PassportAuthFail" ) == 0 ) 149 { 150 xt_free( parser ); 138 139 parser = xt_new(soap_req->xml_parser, soap_req); 140 xt_feed(parser, http_req->reply_body, http_req->body_size); 141 if (http_req->status_code == 500 && 142 (err = xt_find_path(parser->root, "soap:Body/soap:Fault/detail/errorcode")) && 143 err->text_len > 0) { 144 if (strcmp(err->text, "PassportAuthFail") == 0) { 145 xt_free(parser); 151 146 st = MSN_SOAP_REAUTH; 152 147 goto fail; … … 154 149 /* TODO: Handle/report other errors. */ 155 150 } 156 157 xt_handle( parser, NULL, -1 ); 158 xt_free( parser ); 159 } 160 161 if( http_req->status_code != 200 ) 162 soap_req->error = g_strdup( http_req->status_string ); 163 164 st = soap_req->handle_response( soap_req ); 165 166 fail: 167 g_free( soap_req->url ); 168 g_free( soap_req->action ); 169 g_free( soap_req->payload ); 170 g_free( soap_req->error ); 151 152 xt_handle(parser, NULL, -1); 153 xt_free(parser); 154 } 155 156 if (http_req->status_code != 200) { 157 soap_req->error = g_strdup(http_req->status_string); 158 } 159 160 st = soap_req->handle_response(soap_req); 161 162 fail: 163 g_free(soap_req->url); 164 g_free(soap_req->action); 165 g_free(soap_req->payload); 166 g_free(soap_req->error); 171 167 soap_req->url = soap_req->action = soap_req->payload = soap_req->error = NULL; 172 173 if( st == MSN_SOAP_RETRY && --soap_req->ttl ) 174 { 175 msn_soap_send_request( soap_req ); 176 } 177 else if( st == MSN_SOAP_REAUTH ) 178 { 168 169 if (st == MSN_SOAP_RETRY && --soap_req->ttl) { 170 msn_soap_send_request(soap_req); 171 } else if (st == MSN_SOAP_REAUTH) { 179 172 struct msn_data *md = soap_req->ic->proto_data; 180 181 if( !( md->flags & MSN_REAUTHING ) ) 182 { 173 174 if (!(md->flags & MSN_REAUTHING)) { 183 175 /* Nonce shouldn't actually be touched for re-auths. */ 184 msn_soap_passport_sso_request( soap_req->ic, "blaataap");185 md->flags |= MSN_REAUTHING; 176 msn_soap_passport_sso_request(soap_req->ic, "blaataap"); 177 md->flags |= MSN_REAUTHING; 186 178 } 187 md->soapq = g_slist_append( md->soapq, soap_req ); 188 } 189 else 190 { 191 soap_req->free_data( soap_req ); 192 g_free( soap_req ); 193 } 194 } 195 196 static char *msn_soap_abservice_build( const char *body_fmt, const char *scenario, const char *ticket, ... ) 179 md->soapq = g_slist_append(md->soapq, soap_req); 180 } else { 181 soap_req->free_data(soap_req); 182 g_free(soap_req); 183 } 184 } 185 186 static char *msn_soap_abservice_build(const char *body_fmt, const char *scenario, const char *ticket, ...) 197 187 { 198 188 va_list params; 199 189 char *ret, *format, *body; 200 201 format = g_markup_printf_escaped( SOAP_ABSERVICE_PAYLOAD, scenario, ticket);202 203 va_start( params, ticket);204 body = g_strdup_vprintf( body_fmt, params);205 va_end( params);206 207 ret = g_strdup_printf( format, body);208 g_free( body);209 g_free( format);210 190 191 format = g_markup_printf_escaped(SOAP_ABSERVICE_PAYLOAD, scenario, ticket); 192 193 va_start(params, ticket); 194 body = g_strdup_vprintf(body_fmt, params); 195 va_end(params); 196 197 ret = g_strdup_printf(format, body); 198 g_free(body); 199 g_free(format); 200 211 201 return ret; 212 202 } 213 203 214 static void msn_soap_debug_print( const char *headers, const char *payload)204 static void msn_soap_debug_print(const char *headers, const char *payload) 215 205 { 216 206 char *s; 217 218 if ( !getenv( "BITLBEE_DEBUG" ) )207 208 if (!getenv("BITLBEE_DEBUG")) { 219 209 return; 220 221 if( headers ) 222 { 223 if( ( s = strstr( headers, "\r\n\r\n" ) ) ) 224 write( 2, headers, s - headers + 4 ); 225 else 226 write( 2, headers, strlen( headers ) ); 227 } 228 229 if( payload ) 230 { 231 struct xt_node *xt = xt_from_string( payload, 0 ); 232 if( xt ) 233 xt_print( xt ); 234 xt_free_node( xt ); 235 } 236 } 237 238 int msn_soapq_flush( struct im_connection *ic, gboolean resend ) 210 } 211 212 if (headers) { 213 if ((s = strstr(headers, "\r\n\r\n"))) { 214 write(2, headers, s - headers + 4); 215 } else { 216 write(2, headers, strlen(headers)); 217 } 218 } 219 220 if (payload) { 221 struct xt_node *xt = xt_from_string(payload, 0); 222 if (xt) { 223 xt_print(xt); 224 } 225 xt_free_node(xt); 226 } 227 } 228 229 int msn_soapq_flush(struct im_connection *ic, gboolean resend) 239 230 { 240 231 struct msn_data *md = ic->proto_data; 241 242 while ( md->soapq )243 {244 if( resend )245 msn_soap_send_request( (struct msn_soap_req_data*) md->soapq->data );246 else247 msn_soap_free( (struct msn_soap_req_data*) md->soapq->data );248 md->soapq = g_slist_remove( md->soapq, md->soapq->data);249 } 250 251 return MSN_SOAP_OK; 252 } 253 254 static void msn_soap_free( struct msn_soap_req_data *soap_req)255 { 256 soap_req->free_data( soap_req);257 g_free( soap_req->url);258 g_free( soap_req->action);259 g_free( soap_req->payload);260 g_free( soap_req->error);261 g_free( soap_req);232 233 while (md->soapq) { 234 if (resend) { 235 msn_soap_send_request((struct msn_soap_req_data*) md->soapq->data); 236 } else { 237 msn_soap_free((struct msn_soap_req_data*) md->soapq->data); 238 } 239 md->soapq = g_slist_remove(md->soapq, md->soapq->data); 240 } 241 242 return MSN_SOAP_OK; 243 } 244 245 static void msn_soap_free(struct msn_soap_req_data *soap_req) 246 { 247 soap_req->free_data(soap_req); 248 g_free(soap_req->url); 249 g_free(soap_req->action); 250 g_free(soap_req->payload); 251 g_free(soap_req->error); 252 g_free(soap_req); 262 253 } 263 254 … … 265 256 /* passport_sso: Authentication MSNP15+ */ 266 257 267 struct msn_soap_passport_sso_data 268 { 258 struct msn_soap_passport_sso_data { 269 259 char *nonce; 270 260 char *secret; … … 273 263 }; 274 264 275 static int msn_soap_passport_sso_build_request( struct msn_soap_req_data *soap_req)265 static int msn_soap_passport_sso_build_request(struct msn_soap_req_data *soap_req) 276 266 { 277 267 struct msn_soap_passport_sso_data *sd = soap_req->data; 278 268 struct im_connection *ic = soap_req->ic; 279 269 struct msn_data *md = ic->proto_data; 280 char pass[MAX_PASSPORT_PWLEN+1]; 281 282 if( sd->redirect ) 283 { 270 char pass[MAX_PASSPORT_PWLEN + 1]; 271 272 if (sd->redirect) { 284 273 soap_req->url = sd->redirect; 285 274 sd->redirect = NULL; … … 289 278 second, but that's better than not being able to log in at all. :-/ 290 279 else if( g_str_has_suffix( ic->acc->user, "@msn.com" ) ) 291 280 soap_req->url = g_strdup( SOAP_PASSPORT_SSO_URL_MSN ); 292 281 */ 293 else 294 soap_req->url = g_strdup( SOAP_PASSPORT_SSO_URL ); 295 296 strncpy( pass, ic->acc->pass, MAX_PASSPORT_PWLEN ); 282 else { 283 soap_req->url = g_strdup(SOAP_PASSPORT_SSO_URL); 284 } 285 286 strncpy(pass, ic->acc->pass, MAX_PASSPORT_PWLEN); 297 287 pass[MAX_PASSPORT_PWLEN] = '\0'; 298 soap_req->payload = g_markup_printf_escaped( 299 ic->acc->user, pass, md->pp_policy);300 301 return MSN_SOAP_OK; 302 } 303 304 static xt_status msn_soap_passport_sso_token( struct xt_node *node, gpointer data)288 soap_req->payload = g_markup_printf_escaped(SOAP_PASSPORT_SSO_PAYLOAD, 289 ic->acc->user, pass, md->pp_policy); 290 291 return MSN_SOAP_OK; 292 } 293 294 static xt_status msn_soap_passport_sso_token(struct xt_node *node, gpointer data) 305 295 { 306 296 struct msn_soap_req_data *soap_req = data; … … 309 299 struct xt_node *p; 310 300 char *id; 311 312 if ( ( id = xt_find_attr( node, "Id" ) ) == NULL )301 302 if ((id = xt_find_attr(node, "Id")) == NULL) { 313 303 return XT_HANDLED; 314 id += strlen( id ) - 1; 315 if( *id == '1' && 316 ( p = xt_find_path( node, "../../wst:RequestedProofToken/wst:BinarySecret" ) ) && 317 p->text ) 318 sd->secret = g_strdup( p->text ); 319 304 } 305 id += strlen(id) - 1; 306 if (*id == '1' && 307 (p = xt_find_path(node, "../../wst:RequestedProofToken/wst:BinarySecret")) && 308 p->text) { 309 sd->secret = g_strdup(p->text); 310 } 311 320 312 *id -= '1'; 321 if( *id >= 0 && *id < sizeof( md->tokens ) / sizeof( md->tokens[0] ) ) 322 { 323 g_free( md->tokens[(int)*id] ); 324 md->tokens[(int)*id] = g_strdup( node->text ); 325 } 326 313 if (*id >= 0 && *id < sizeof(md->tokens) / sizeof(md->tokens[0])) { 314 g_free(md->tokens[(int) *id]); 315 md->tokens[(int) *id] = g_strdup(node->text); 316 } 317 327 318 return XT_HANDLED; 328 319 } 329 320 330 static xt_status msn_soap_passport_failure( struct xt_node *node, gpointer data)321 static xt_status msn_soap_passport_failure(struct xt_node *node, gpointer data) 331 322 { 332 323 struct msn_soap_req_data *soap_req = data; 333 324 struct msn_soap_passport_sso_data *sd = soap_req->data; 334 struct xt_node *code = xt_find_node( node->children, "faultcode");335 struct xt_node *string = xt_find_node( node->children, "faultstring");325 struct xt_node *code = xt_find_node(node->children, "faultcode"); 326 struct xt_node *string = xt_find_node(node->children, "faultstring"); 336 327 struct xt_node *url; 337 338 if( code == NULL || code->text_len == 0 ) 339 sd->error = g_strdup( "Unknown error" ); 340 else if( strcmp( code->text, "psf:Redirect" ) == 0 && 341 ( url = xt_find_node( node->children, "psf:redirectUrl" ) ) && 342 url->text_len > 0 ) 343 sd->redirect = g_strdup( url->text ); 344 else 345 sd->error = g_strdup_printf( "%s (%s)", code->text, string && string->text_len ? 346 string->text : "no description available" ); 347 328 329 if (code == NULL || code->text_len == 0) { 330 sd->error = g_strdup("Unknown error"); 331 } else if (strcmp(code->text, "psf:Redirect") == 0 && 332 (url = xt_find_node(node->children, "psf:redirectUrl")) && 333 url->text_len > 0) { 334 sd->redirect = g_strdup(url->text); 335 } else { 336 sd->error = g_strdup_printf("%s (%s)", code->text, string && string->text_len ? 337 string->text : "no description available"); 338 } 339 348 340 return XT_HANDLED; 349 341 } … … 355 347 }; 356 348 357 static char *msn_key_fuckery( char *key, int key_len, char *type)358 { 359 unsigned char hash1[20 +strlen(type)+1];349 static char *msn_key_fuckery(char *key, int key_len, char *type) 350 { 351 unsigned char hash1[20 + strlen(type) + 1]; 360 352 unsigned char hash2[20]; 361 353 char *ret; 362 363 sha1_hmac( key, key_len, type, 0, hash1);364 strcpy( (char*) hash1 + 20, type);365 sha1_hmac( key, key_len, (char*) hash1, sizeof( hash1 ) - 1, hash2);366 354 355 sha1_hmac(key, key_len, type, 0, hash1); 356 strcpy((char *) hash1 + 20, type); 357 sha1_hmac(key, key_len, (char *) hash1, sizeof(hash1) - 1, hash2); 358 367 359 /* This is okay as hash1 is read completely before it's overwritten. */ 368 sha1_hmac( key, key_len, (char*) hash1, 20, hash1);369 sha1_hmac( key, key_len, (char*) hash1, sizeof( hash1 ) - 1, hash1);370 371 ret = g_malloc( 24);372 memcpy( ret, hash2, 20);373 memcpy( ret + 20, hash1, 4);360 sha1_hmac(key, key_len, (char *) hash1, 20, hash1); 361 sha1_hmac(key, key_len, (char *) hash1, sizeof(hash1) - 1, hash1); 362 363 ret = g_malloc(24); 364 memcpy(ret, hash2, 20); 365 memcpy(ret + 20, hash1, 4); 374 366 return ret; 375 367 } 376 368 377 static int msn_soap_passport_sso_handle_response( struct msn_soap_req_data *soap_req)369 static int msn_soap_passport_sso_handle_response(struct msn_soap_req_data *soap_req) 378 370 { 379 371 struct msn_soap_passport_sso_data *sd = soap_req->data; … … 383 375 int key1_len; 384 376 unsigned char *padnonce, *des3res; 385 struct 386 {377 378 struct { 387 379 unsigned int uStructHeaderSize; // 28. Does not count data 388 380 unsigned int uCryptMode; // CRYPT_MODE_CBC (1) … … 396 388 unsigned char cipherbytes[72]; 397 389 } blurb = { 398 GUINT32_TO_LE( 28),399 GUINT32_TO_LE( 1),400 GUINT32_TO_LE( 0x6603),401 GUINT32_TO_LE( 0x8004),402 GUINT32_TO_LE( 8),403 GUINT32_TO_LE( 20),404 GUINT32_TO_LE( 72),390 GUINT32_TO_LE(28), 391 GUINT32_TO_LE(1), 392 GUINT32_TO_LE(0x6603), 393 GUINT32_TO_LE(0x8004), 394 GUINT32_TO_LE(8), 395 GUINT32_TO_LE(20), 396 GUINT32_TO_LE(72), 405 397 }; 406 407 if ( sd->redirect )398 399 if (sd->redirect) { 408 400 return MSN_SOAP_RETRY; 409 410 if( md->soapq ) 411 { 412 md->flags &= ~MSN_REAUTHING; 413 return msn_soapq_flush( ic, TRUE ); 414 } 415 416 if( sd->secret == NULL ) 417 { 418 msn_auth_got_passport_token( ic, NULL, sd->error ? sd->error : soap_req->error ); 401 } 402 403 if (md->soapq) { 404 md->flags &= ~MSN_REAUTHING; 405 return msn_soapq_flush(ic, TRUE); 406 } 407 408 if (sd->secret == NULL) { 409 msn_auth_got_passport_token(ic, NULL, sd->error ? sd->error : soap_req->error); 419 410 return MSN_SOAP_OK; 420 411 } 421 412 422 key1_len = base64_decode( sd->secret, (unsigned char**) &key1);423 424 key2 = msn_key_fuckery( key1, key1_len, "WS-SecureConversationSESSION KEY HASH");425 key3 = msn_key_fuckery( key1, key1_len, "WS-SecureConversationSESSION KEY ENCRYPTION");426 427 sha1_hmac( key2, 24, sd->nonce, 0, blurb.hash);428 padnonce = g_malloc( strlen( sd->nonce ) + 8);429 strcpy( (char*) padnonce, sd->nonce);430 memset( padnonce + strlen( sd->nonce ), 8, 8);431 432 random_bytes( blurb.iv, 8);433 434 ssl_des3_encrypt( (unsigned char*) key3, 24, padnonce, strlen( sd->nonce ) + 8, blurb.iv, &des3res);435 memcpy( blurb.cipherbytes, des3res, 72);436 437 blurb64 = base64_encode( (unsigned char*) &blurb, sizeof( blurb ));438 msn_auth_got_passport_token( ic, blurb64, NULL);439 440 g_free( padnonce);441 g_free( blurb64);442 g_free( des3res);443 g_free( key1);444 g_free( key2);445 g_free( key3);446 447 return MSN_SOAP_OK; 448 } 449 450 static int msn_soap_passport_sso_free_data( struct msn_soap_req_data *soap_req)413 key1_len = base64_decode(sd->secret, (unsigned char **) &key1); 414 415 key2 = msn_key_fuckery(key1, key1_len, "WS-SecureConversationSESSION KEY HASH"); 416 key3 = msn_key_fuckery(key1, key1_len, "WS-SecureConversationSESSION KEY ENCRYPTION"); 417 418 sha1_hmac(key2, 24, sd->nonce, 0, blurb.hash); 419 padnonce = g_malloc(strlen(sd->nonce) + 8); 420 strcpy((char *) padnonce, sd->nonce); 421 memset(padnonce + strlen(sd->nonce), 8, 8); 422 423 random_bytes(blurb.iv, 8); 424 425 ssl_des3_encrypt((unsigned char *) key3, 24, padnonce, strlen(sd->nonce) + 8, blurb.iv, &des3res); 426 memcpy(blurb.cipherbytes, des3res, 72); 427 428 blurb64 = base64_encode((unsigned char *) &blurb, sizeof(blurb)); 429 msn_auth_got_passport_token(ic, blurb64, NULL); 430 431 g_free(padnonce); 432 g_free(blurb64); 433 g_free(des3res); 434 g_free(key1); 435 g_free(key2); 436 g_free(key3); 437 438 return MSN_SOAP_OK; 439 } 440 441 static int msn_soap_passport_sso_free_data(struct msn_soap_req_data *soap_req) 451 442 { 452 443 struct msn_soap_passport_sso_data *sd = soap_req->data; 453 454 g_free( sd->nonce);455 g_free( sd->secret);456 g_free( sd->error);457 g_free( sd->redirect);458 g_free( sd);459 460 return MSN_SOAP_OK; 461 } 462 463 int msn_soap_passport_sso_request( struct im_connection *ic, const char *nonce)464 { 465 struct msn_soap_passport_sso_data *sd = g_new0( struct msn_soap_passport_sso_data, 1);466 467 sd->nonce = g_strdup( nonce);468 469 return msn_soap_start( 470 471 472 msn_soap_passport_sso_free_data);444 445 g_free(sd->nonce); 446 g_free(sd->secret); 447 g_free(sd->error); 448 g_free(sd->redirect); 449 g_free(sd); 450 451 return MSN_SOAP_OK; 452 } 453 454 int msn_soap_passport_sso_request(struct im_connection *ic, const char *nonce) 455 { 456 struct msn_soap_passport_sso_data *sd = g_new0(struct msn_soap_passport_sso_data, 1); 457 458 sd->nonce = g_strdup(nonce); 459 460 return msn_soap_start(ic, sd, msn_soap_passport_sso_build_request, 461 msn_soap_passport_sso_parser, 462 msn_soap_passport_sso_handle_response, 463 msn_soap_passport_sso_free_data); 473 464 } 474 465 … … 476 467 /* memlist: Fetching the membership list (NOT address book) */ 477 468 478 static int msn_soap_memlist_build_request( struct msn_soap_req_data *soap_req)479 { 480 struct msn_data *md = soap_req->ic->proto_data; 481 482 soap_req->url = g_strdup( SOAP_MEMLIST_URL);483 soap_req->action = g_strdup( SOAP_MEMLIST_ACTION);484 soap_req->payload = msn_soap_abservice_build( SOAP_MEMLIST_PAYLOAD, "Initial", md->tokens[1]);485 469 static int msn_soap_memlist_build_request(struct msn_soap_req_data *soap_req) 470 { 471 struct msn_data *md = soap_req->ic->proto_data; 472 473 soap_req->url = g_strdup(SOAP_MEMLIST_URL); 474 soap_req->action = g_strdup(SOAP_MEMLIST_ACTION); 475 soap_req->payload = msn_soap_abservice_build(SOAP_MEMLIST_PAYLOAD, "Initial", md->tokens[1]); 476 486 477 return 1; 487 478 } 488 479 489 static xt_status msn_soap_memlist_member( struct xt_node *node, gpointer data)480 static xt_status msn_soap_memlist_member(struct xt_node *node, gpointer data) 490 481 { 491 482 bee_user_t *bu; … … 495 486 struct msn_soap_req_data *soap_req = data; 496 487 struct im_connection *ic = soap_req->ic; 497 498 if ( ( p = xt_find_path( node, "../../MemberRole" ) ) )488 489 if ((p = xt_find_path(node, "../../MemberRole"))) { 499 490 role = p->text; 500 501 if( ( p = xt_find_node( node->children, "PassportName" ) ) ) 491 } 492 493 if ((p = xt_find_node(node->children, "PassportName"))) { 502 494 handle = p->text; 503 504 if( !role || !handle || 505 !( ( bu = bee_user_by_handle( ic->bee, ic, handle ) ) || 506 ( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) ) ) 495 } 496 497 if (!role || !handle || 498 !((bu = bee_user_by_handle(ic->bee, ic, handle)) || 499 (bu = bee_user_new(ic->bee, ic, handle, 0)))) { 507 500 return XT_HANDLED; 508 501 } 502 509 503 bd = bu->data; 510 if( strcmp( role, "Allow" ) == 0 ) 511 { 504 if (strcmp(role, "Allow") == 0) { 512 505 bd->flags |= MSN_BUDDY_AL; 513 ic->permit = g_slist_prepend( ic->permit, g_strdup( handle ) ); 514 } 515 else if( strcmp( role, "Block" ) == 0 ) 516 { 506 ic->permit = g_slist_prepend(ic->permit, g_strdup(handle)); 507 } else if (strcmp(role, "Block") == 0) { 517 508 bd->flags |= MSN_BUDDY_BL; 518 ic->deny = g_slist_prepend( ic->deny, g_strdup( handle ) ); 519 } 520 else if( strcmp( role, "Reverse" ) == 0 ) 509 ic->deny = g_slist_prepend(ic->deny, g_strdup(handle)); 510 } else if (strcmp(role, "Reverse") == 0) { 521 511 bd->flags |= MSN_BUDDY_RL; 522 else if( strcmp( role, "Pending" ) == 0 )512 } else if (strcmp(role, "Pending") == 0) { 523 513 bd->flags |= MSN_BUDDY_PL; 524 525 if( getenv( "BITLBEE_DEBUG" ) ) 526 fprintf( stderr, "%p %s %d\n", bu, handle, bd->flags ); 527 514 } 515 516 if (getenv("BITLBEE_DEBUG")) { 517 fprintf(stderr, "%p %s %d\n", bu, handle, bd->flags); 518 } 519 528 520 return XT_HANDLED; 529 521 } … … 534 526 }; 535 527 536 static int msn_soap_memlist_handle_response( struct msn_soap_req_data *soap_req)537 { 538 msn_soap_addressbook_request( soap_req->ic);539 540 return MSN_SOAP_OK; 541 } 542 543 static int msn_soap_memlist_free_data( struct msn_soap_req_data *soap_req)528 static int msn_soap_memlist_handle_response(struct msn_soap_req_data *soap_req) 529 { 530 msn_soap_addressbook_request(soap_req->ic); 531 532 return MSN_SOAP_OK; 533 } 534 535 static int msn_soap_memlist_free_data(struct msn_soap_req_data *soap_req) 544 536 { 545 537 return 0; 546 538 } 547 539 548 int msn_soap_memlist_request( struct im_connection *ic)549 { 550 return msn_soap_start( 551 552 553 msn_soap_memlist_free_data);540 int msn_soap_memlist_request(struct im_connection *ic) 541 { 542 return msn_soap_start(ic, NULL, msn_soap_memlist_build_request, 543 msn_soap_memlist_parser, 544 msn_soap_memlist_handle_response, 545 msn_soap_memlist_free_data); 554 546 } 555 547 556 548 /* Variant: Adding/Removing people */ 557 struct msn_soap_memlist_edit_data 558 { 549 struct msn_soap_memlist_edit_data { 559 550 char *handle; 560 551 gboolean add; … … 562 553 }; 563 554 564 static int msn_soap_memlist_edit_build_request( struct msn_soap_req_data *soap_req)555 static int msn_soap_memlist_edit_build_request(struct msn_soap_req_data *soap_req) 565 556 { 566 557 struct msn_data *md = soap_req->ic->proto_data; 567 558 struct msn_soap_memlist_edit_data *med = soap_req->data; 568 559 char *add, *scenario, *list; 569 570 soap_req->url = g_strdup( SOAP_MEMLIST_URL ); 571 if( med->add ) 572 { 573 soap_req->action = g_strdup( SOAP_MEMLIST_ADD_ACTION ); 560 561 soap_req->url = g_strdup(SOAP_MEMLIST_URL); 562 if (med->add) { 563 soap_req->action = g_strdup(SOAP_MEMLIST_ADD_ACTION); 574 564 add = "Add"; 575 } 576 else 577 { 578 soap_req->action = g_strdup( SOAP_MEMLIST_DEL_ACTION ); 565 } else { 566 soap_req->action = g_strdup(SOAP_MEMLIST_DEL_ACTION); 579 567 add = "Delete"; 580 568 } 581 switch( med->list ) 582 { 569 switch (med->list) { 583 570 case MSN_BUDDY_AL: 584 571 scenario = "BlockUnblock"; … … 599 586 break; 600 587 } 601 soap_req->payload = msn_soap_abservice_build( 602 scenario, md->tokens[1], add, list, med->handle, add);603 588 soap_req->payload = msn_soap_abservice_build(SOAP_MEMLIST_EDIT_PAYLOAD, 589 scenario, md->tokens[1], add, list, med->handle, add); 590 604 591 return 1; 605 592 } 606 593 607 static int msn_soap_memlist_edit_handle_response( struct msn_soap_req_data *soap_req)608 { 609 return MSN_SOAP_OK; 610 } 611 612 static int msn_soap_memlist_edit_free_data( struct msn_soap_req_data *soap_req)594 static int msn_soap_memlist_edit_handle_response(struct msn_soap_req_data *soap_req) 595 { 596 return MSN_SOAP_OK; 597 } 598 599 static int msn_soap_memlist_edit_free_data(struct msn_soap_req_data *soap_req) 613 600 { 614 601 struct msn_soap_memlist_edit_data *med = soap_req->data; 615 616 g_free( med->handle);617 g_free( med);618 602 603 g_free(med->handle); 604 g_free(med); 605 619 606 return 0; 620 607 } 621 608 622 int msn_soap_memlist_edit( struct im_connection *ic, const char *handle, gboolean add, int list)609 int msn_soap_memlist_edit(struct im_connection *ic, const char *handle, gboolean add, int list) 623 610 { 624 611 struct msn_soap_memlist_edit_data *med; 625 626 med = g_new0( struct msn_soap_memlist_edit_data, 1);627 med->handle = g_strdup( handle);612 613 med = g_new0(struct msn_soap_memlist_edit_data, 1); 614 med->handle = g_strdup(handle); 628 615 med->add = add; 629 616 med->list = list; 630 631 return msn_soap_start( 632 633 634 msn_soap_memlist_edit_free_data);617 618 return msn_soap_start(ic, med, msn_soap_memlist_edit_build_request, 619 NULL, 620 msn_soap_memlist_edit_handle_response, 621 msn_soap_memlist_edit_free_data); 635 622 } 636 623 … … 638 625 /* addressbook: Fetching the membership list (NOT address book) */ 639 626 640 static int msn_soap_addressbook_build_request( struct msn_soap_req_data *soap_req)641 { 642 struct msn_data *md = soap_req->ic->proto_data; 643 644 soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL);645 soap_req->action = g_strdup( SOAP_ADDRESSBOOK_ACTION);646 soap_req->payload = msn_soap_abservice_build( SOAP_ADDRESSBOOK_PAYLOAD, "Initial", md->tokens[1]);647 627 static int msn_soap_addressbook_build_request(struct msn_soap_req_data *soap_req) 628 { 629 struct msn_data *md = soap_req->ic->proto_data; 630 631 soap_req->url = g_strdup(SOAP_ADDRESSBOOK_URL); 632 soap_req->action = g_strdup(SOAP_ADDRESSBOOK_ACTION); 633 soap_req->payload = msn_soap_abservice_build(SOAP_ADDRESSBOOK_PAYLOAD, "Initial", md->tokens[1]); 634 648 635 return 1; 649 636 } 650 637 651 static xt_status msn_soap_addressbook_group( struct xt_node *node, gpointer data)638 static xt_status msn_soap_addressbook_group(struct xt_node *node, gpointer data) 652 639 { 653 640 struct xt_node *p; … … 655 642 struct msn_soap_req_data *soap_req = data; 656 643 struct msn_data *md = soap_req->ic->proto_data; 657 658 if ( ( p = xt_find_path( node, "../groupId" ) ) )644 645 if ((p = xt_find_path(node, "../groupId"))) { 659 646 id = p->text; 660 661 if( ( p = xt_find_node( node->children, "name" ) ) ) 647 } 648 649 if ((p = xt_find_node(node->children, "name"))) { 662 650 name = p->text; 663 664 if( id && name ) 665 { 666 struct msn_group *mg = g_new0( struct msn_group, 1 ); 667 mg->id = g_strdup( id ); 668 mg->name = g_strdup( name ); 669 md->groups = g_slist_prepend( md->groups, mg ); 670 } 671 672 if( getenv( "BITLBEE_DEBUG" ) ) 673 fprintf( stderr, "%s %s\n", id, name ); 674 651 } 652 653 if (id && name) { 654 struct msn_group *mg = g_new0(struct msn_group, 1); 655 mg->id = g_strdup(id); 656 mg->name = g_strdup(name); 657 md->groups = g_slist_prepend(md->groups, mg); 658 } 659 660 if (getenv("BITLBEE_DEBUG")) { 661 fprintf(stderr, "%s %s\n", id, name); 662 } 663 675 664 return XT_HANDLED; 676 665 } 677 666 678 static xt_status msn_soap_addressbook_contact( struct xt_node *node, gpointer data)667 static xt_status msn_soap_addressbook_contact(struct xt_node *node, gpointer data) 679 668 { 680 669 bee_user_t *bu; … … 682 671 struct xt_node *p; 683 672 char *id = NULL, *type = NULL, *handle = NULL, *is_msgr = "false", 684 673 *display_name = NULL, *group_id = NULL; 685 674 struct msn_soap_req_data *soap_req = data; 686 675 struct im_connection *ic = soap_req->ic; 687 676 struct msn_group *group; 688 689 if ( ( p = xt_find_path( node, "../contactId" ) ) )677 678 if ((p = xt_find_path(node, "../contactId"))) { 690 679 id = p->text; 691 if( ( p = xt_find_node( node->children, "contactType" ) ) ) 680 } 681 if ((p = xt_find_node(node->children, "contactType"))) { 692 682 type = p->text; 693 if( ( p = xt_find_node( node->children, "passportName" ) ) ) 683 } 684 if ((p = xt_find_node(node->children, "passportName"))) { 694 685 handle = p->text; 695 if( ( p = xt_find_node( node->children, "displayName" ) ) ) 686 } 687 if ((p = xt_find_node(node->children, "displayName"))) { 696 688 display_name = p->text; 697 if( ( p = xt_find_node( node->children, "isMessengerUser" ) ) ) 689 } 690 if ((p = xt_find_node(node->children, "isMessengerUser"))) { 698 691 is_msgr = p->text; 699 if( ( p = xt_find_path( node, "groupIds/guid" ) ) ) 692 } 693 if ((p = xt_find_path(node, "groupIds/guid"))) { 700 694 group_id = p->text; 701 702 if( type && g_strcasecmp( type, "me" ) == 0 ) 703 {704 set_t *set = set_find( &ic->acc->set, "display_name");705 g_free( set->value);706 set->value = g_strdup( display_name);707 695 } 696 697 if (type && g_strcasecmp(type, "me") == 0) { 698 set_t *set = set_find(&ic->acc->set, "display_name"); 699 g_free(set->value); 700 set->value = g_strdup(display_name); 701 708 702 /* Try to fetch the profile; if the user has one, that's where 709 703 we can find the persistent display_name. */ 710 if( ( p = xt_find_node( node->children, "CID" ) ) && p->text ) 711 msn_soap_profile_get( ic, p->text ); 712 704 if ((p = xt_find_node(node->children, "CID")) && p->text) { 705 msn_soap_profile_get(ic, p->text); 706 } 707 713 708 return XT_HANDLED; 714 709 } 715 716 if ( !bool2int( is_msgr ) || handle == NULL )710 711 if (!bool2int(is_msgr) || handle == NULL) { 717 712 return XT_HANDLED; 718 719 if( !( bu = bee_user_by_handle( ic->bee, ic, handle ) ) && 720 !( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) ) 713 } 714 715 if (!(bu = bee_user_by_handle(ic->bee, ic, handle)) && 716 !(bu = bee_user_new(ic->bee, ic, handle, 0))) { 721 717 return XT_HANDLED; 722 718 } 719 723 720 bd = bu->data; 724 721 bd->flags |= MSN_BUDDY_FL; 725 g_free( bd->cid ); 726 bd->cid = g_strdup( id ); 727 728 imcb_rename_buddy( ic, handle, display_name ); 729 730 if( group_id && ( group = msn_group_by_id( ic, group_id ) ) ) 731 imcb_add_buddy( ic, handle, group->name ); 732 733 if( getenv( "BITLBEE_DEBUG" ) ) 734 fprintf( stderr, "%s %s %s %s\n", id, type, handle, display_name ); 735 722 g_free(bd->cid); 723 bd->cid = g_strdup(id); 724 725 imcb_rename_buddy(ic, handle, display_name); 726 727 if (group_id && (group = msn_group_by_id(ic, group_id))) { 728 imcb_add_buddy(ic, handle, group->name); 729 } 730 731 if (getenv("BITLBEE_DEBUG")) { 732 fprintf(stderr, "%s %s %s %s\n", id, type, handle, display_name); 733 } 734 736 735 return XT_HANDLED; 737 736 } … … 743 742 }; 744 743 745 static int msn_soap_addressbook_handle_response( struct msn_soap_req_data *soap_req)744 static int msn_soap_addressbook_handle_response(struct msn_soap_req_data *soap_req) 746 745 { 747 746 GSList *l; 748 747 int wtf = 0; 749 750 for( l = soap_req->ic->bee->users; l; l = l->next ) 751 { 748 749 for (l = soap_req->ic->bee->users; l; l = l->next) { 752 750 struct bee_user *bu = l->data; 753 751 struct msn_buddy_data *bd = bu->data; 754 755 if( bu->ic == soap_req->ic && bd ) 756 { 757 msn_buddy_ask( bu ); 758 759 if( ( bd->flags & ( MSN_BUDDY_AL | MSN_BUDDY_BL ) ) == 760 ( MSN_BUDDY_AL | MSN_BUDDY_BL ) ) 761 { 752 753 if (bu->ic == soap_req->ic && bd) { 754 msn_buddy_ask(bu); 755 756 if ((bd->flags & (MSN_BUDDY_AL | MSN_BUDDY_BL)) == 757 (MSN_BUDDY_AL | MSN_BUDDY_BL)) { 762 758 /* both allow and block, delete block, add wtf */ 763 759 bd->flags &= ~MSN_BUDDY_BL; … … 766 762 767 763 768 if( ( bd->flags & ( MSN_BUDDY_AL | MSN_BUDDY_BL ) ) == 0 ) 769 { 764 if ((bd->flags & (MSN_BUDDY_AL | MSN_BUDDY_BL)) == 0) { 770 765 /* neither allow or block, add allow */ 771 766 bd->flags |= MSN_BUDDY_AL; … … 773 768 } 774 769 } 775 776 if( wtf ) 777 imcb_log( soap_req->ic, "Warning: %d contacts were in both your " 778 "block and your allow list. Assuming they're all " 779 "allowed. Use the official WLM client once to fix " 780 "this.", wtf ); 781 782 msn_auth_got_contact_list( soap_req->ic ); 783 784 return MSN_SOAP_OK; 785 } 786 787 static int msn_soap_addressbook_free_data( struct msn_soap_req_data *soap_req ) 770 771 if (wtf) { 772 imcb_log(soap_req->ic, "Warning: %d contacts were in both your " 773 "block and your allow list. Assuming they're all " 774 "allowed. Use the official WLM client once to fix " 775 "this.", wtf); 776 } 777 778 msn_auth_got_contact_list(soap_req->ic); 779 780 return MSN_SOAP_OK; 781 } 782 783 static int msn_soap_addressbook_free_data(struct msn_soap_req_data *soap_req) 788 784 { 789 785 return 0; 790 786 } 791 787 792 int msn_soap_addressbook_request( struct im_connection *ic)793 { 794 return msn_soap_start( 795 796 797 msn_soap_addressbook_free_data);788 int msn_soap_addressbook_request(struct im_connection *ic) 789 { 790 return msn_soap_start(ic, NULL, msn_soap_addressbook_build_request, 791 msn_soap_addressbook_parser, 792 msn_soap_addressbook_handle_response, 793 msn_soap_addressbook_free_data); 798 794 } 799 795 800 796 /* Variant: Change our display name. */ 801 static int msn_soap_ab_namechange_build_request( struct msn_soap_req_data *soap_req)802 { 803 struct msn_data *md = soap_req->ic->proto_data; 804 805 soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL);806 soap_req->action = g_strdup( SOAP_AB_NAMECHANGE_ACTION);807 soap_req->payload = msn_soap_abservice_build( 808 "Timer", md->tokens[1], (char *) soap_req->data);809 797 static int msn_soap_ab_namechange_build_request(struct msn_soap_req_data *soap_req) 798 { 799 struct msn_data *md = soap_req->ic->proto_data; 800 801 soap_req->url = g_strdup(SOAP_ADDRESSBOOK_URL); 802 soap_req->action = g_strdup(SOAP_AB_NAMECHANGE_ACTION); 803 soap_req->payload = msn_soap_abservice_build(SOAP_AB_NAMECHANGE_PAYLOAD, 804 "Timer", md->tokens[1], (char *) soap_req->data); 805 810 806 return 1; 811 807 } 812 808 813 static int msn_soap_ab_namechange_handle_response( struct msn_soap_req_data *soap_req)809 static int msn_soap_ab_namechange_handle_response(struct msn_soap_req_data *soap_req) 814 810 { 815 811 /* TODO: Ack the change? Not sure what the NAKs look like.. */ … … 817 813 } 818 814 819 static int msn_soap_ab_namechange_free_data( struct msn_soap_req_data *soap_req)820 { 821 g_free( soap_req->data);815 static int msn_soap_ab_namechange_free_data(struct msn_soap_req_data *soap_req) 816 { 817 g_free(soap_req->data); 822 818 return 0; 823 819 } 824 820 825 int msn_soap_addressbook_set_display_name( struct im_connection *ic, const char *new)826 { 827 return msn_soap_start( ic, g_strdup( new),828 829 830 831 msn_soap_ab_namechange_free_data);821 int msn_soap_addressbook_set_display_name(struct im_connection *ic, const char *new) 822 { 823 return msn_soap_start(ic, g_strdup(new), 824 msn_soap_ab_namechange_build_request, 825 NULL, 826 msn_soap_ab_namechange_handle_response, 827 msn_soap_ab_namechange_free_data); 832 828 } 833 829 834 830 /* Add a contact. */ 835 static int msn_soap_ab_contact_add_build_request( struct msn_soap_req_data *soap_req)831 static int msn_soap_ab_contact_add_build_request(struct msn_soap_req_data *soap_req) 836 832 { 837 833 struct msn_data *md = soap_req->ic->proto_data; 838 834 bee_user_t *bu = soap_req->data; 839 840 soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL ); 841 soap_req->action = g_strdup( SOAP_AB_CONTACT_ADD_ACTION ); 842 soap_req->payload = msn_soap_abservice_build( SOAP_AB_CONTACT_ADD_PAYLOAD, 843 "ContactSave", md->tokens[1], bu->handle, bu->fullname ? bu->fullname : bu->handle ); 844 835 836 soap_req->url = g_strdup(SOAP_ADDRESSBOOK_URL); 837 soap_req->action = g_strdup(SOAP_AB_CONTACT_ADD_ACTION); 838 soap_req->payload = msn_soap_abservice_build(SOAP_AB_CONTACT_ADD_PAYLOAD, 839 "ContactSave", md->tokens[1], bu->handle, 840 bu->fullname ? bu->fullname : bu->handle); 841 845 842 return 1; 846 843 } 847 844 848 static xt_status msn_soap_ab_contact_add_cid( struct xt_node *node, gpointer data)845 static xt_status msn_soap_ab_contact_add_cid(struct xt_node *node, gpointer data) 849 846 { 850 847 struct msn_soap_req_data *soap_req = data; 851 848 bee_user_t *bu = soap_req->data; 852 849 struct msn_buddy_data *bd = bu->data; 853 854 g_free( bd->cid);855 bd->cid = g_strdup( node->text);856 850 851 g_free(bd->cid); 852 bd->cid = g_strdup(node->text); 853 857 854 return XT_HANDLED; 858 855 } … … 863 860 }; 864 861 865 static int msn_soap_ab_contact_add_handle_response( struct msn_soap_req_data *soap_req)862 static int msn_soap_ab_contact_add_handle_response(struct msn_soap_req_data *soap_req) 866 863 { 867 864 /* TODO: Ack the change? Not sure what the NAKs look like.. */ … … 869 866 } 870 867 871 static int msn_soap_ab_contact_add_free_data( struct msn_soap_req_data *soap_req)868 static int msn_soap_ab_contact_add_free_data(struct msn_soap_req_data *soap_req) 872 869 { 873 870 return 0; 874 871 } 875 872 876 int msn_soap_ab_contact_add( struct im_connection *ic, bee_user_t *bu)877 { 878 return msn_soap_start( 879 880 881 882 msn_soap_ab_contact_add_free_data);873 int msn_soap_ab_contact_add(struct im_connection *ic, bee_user_t *bu) 874 { 875 return msn_soap_start(ic, bu, 876 msn_soap_ab_contact_add_build_request, 877 msn_soap_ab_contact_add_parser, 878 msn_soap_ab_contact_add_handle_response, 879 msn_soap_ab_contact_add_free_data); 883 880 } 884 881 885 882 /* Remove a contact. */ 886 static int msn_soap_ab_contact_del_build_request( struct msn_soap_req_data *soap_req)883 static int msn_soap_ab_contact_del_build_request(struct msn_soap_req_data *soap_req) 887 884 { 888 885 struct msn_data *md = soap_req->ic->proto_data; 889 886 const char *cid = soap_req->data; 890 891 soap_req->url = g_strdup( SOAP_ADDRESSBOOK_URL);892 soap_req->action = g_strdup( SOAP_AB_CONTACT_DEL_ACTION);893 soap_req->payload = msn_soap_abservice_build( 894 "Timer", md->tokens[1], cid);895 887 888 soap_req->url = g_strdup(SOAP_ADDRESSBOOK_URL); 889 soap_req->action = g_strdup(SOAP_AB_CONTACT_DEL_ACTION); 890 soap_req->payload = msn_soap_abservice_build(SOAP_AB_CONTACT_DEL_PAYLOAD, 891 "Timer", md->tokens[1], cid); 892 896 893 return 1; 897 894 } 898 895 899 static int msn_soap_ab_contact_del_handle_response( struct msn_soap_req_data *soap_req)896 static int msn_soap_ab_contact_del_handle_response(struct msn_soap_req_data *soap_req) 900 897 { 901 898 /* TODO: Ack the change? Not sure what the NAKs look like.. */ … … 903 900 } 904 901 905 static int msn_soap_ab_contact_del_free_data( struct msn_soap_req_data *soap_req)906 { 907 g_free( soap_req->data);902 static int msn_soap_ab_contact_del_free_data(struct msn_soap_req_data *soap_req) 903 { 904 g_free(soap_req->data); 908 905 return 0; 909 906 } 910 907 911 int msn_soap_ab_contact_del( struct im_connection *ic, bee_user_t *bu)908 int msn_soap_ab_contact_del(struct im_connection *ic, bee_user_t *bu) 912 909 { 913 910 struct msn_buddy_data *bd = bu->data; 914 915 return msn_soap_start( ic, g_strdup( bd->cid),916 917 918 919 msn_soap_ab_contact_del_free_data);911 912 return msn_soap_start(ic, g_strdup(bd->cid), 913 msn_soap_ab_contact_del_build_request, 914 NULL, 915 msn_soap_ab_contact_del_handle_response, 916 msn_soap_ab_contact_del_free_data); 920 917 } 921 918 … … 923 920 924 921 /* Storage stuff: Fetch profile. */ 925 static int msn_soap_profile_get_build_request( struct msn_soap_req_data *soap_req)926 { 927 struct msn_data *md = soap_req->ic->proto_data; 928 929 soap_req->url = g_strdup( SOAP_STORAGE_URL);930 soap_req->action = g_strdup( SOAP_PROFILE_GET_ACTION);931 soap_req->payload = g_markup_printf_escaped( 932 md->tokens[3], (char*) soap_req->data);933 922 static int msn_soap_profile_get_build_request(struct msn_soap_req_data *soap_req) 923 { 924 struct msn_data *md = soap_req->ic->proto_data; 925 926 soap_req->url = g_strdup(SOAP_STORAGE_URL); 927 soap_req->action = g_strdup(SOAP_PROFILE_GET_ACTION); 928 soap_req->payload = g_markup_printf_escaped(SOAP_PROFILE_GET_PAYLOAD, 929 md->tokens[3], (char *) soap_req->data); 930 934 931 return 1; 935 932 } 936 933 937 static xt_status msn_soap_profile_get_result( struct xt_node *node, gpointer data)934 static xt_status msn_soap_profile_get_result(struct xt_node *node, gpointer data) 938 935 { 939 936 struct msn_soap_req_data *soap_req = data; … … 941 938 struct msn_data *md = soap_req->ic->proto_data; 942 939 struct xt_node *dn; 943 944 if( ( dn = xt_find_node( node->children, "DisplayName" ) ) && dn->text ) 945 { 946 set_t *set = set_find( &ic->acc->set, "display_name" ); 947 g_free( set->value ); 948 set->value = g_strdup( dn->text ); 949 940 941 if ((dn = xt_find_node(node->children, "DisplayName")) && dn->text) { 942 set_t *set = set_find(&ic->acc->set, "display_name"); 943 g_free(set->value); 944 set->value = g_strdup(dn->text); 945 950 946 md->flags |= MSN_GOT_PROFILE_DN; 951 947 } 952 948 953 949 return XT_HANDLED; 954 950 } 955 951 956 static xt_status msn_soap_profile_get_rid( struct xt_node *node, gpointer data)952 static xt_status msn_soap_profile_get_rid(struct xt_node *node, gpointer data) 957 953 { 958 954 struct msn_soap_req_data *soap_req = data; 959 955 struct msn_data *md = soap_req->ic->proto_data; 960 961 g_free( md->profile_rid);962 md->profile_rid = g_strdup( node->text);963 956 957 g_free(md->profile_rid); 958 md->profile_rid = g_strdup(node->text); 959 964 960 return XT_HANDLED; 965 961 } … … 971 967 }; 972 968 973 static int msn_soap_profile_get_handle_response( struct msn_soap_req_data *soap_req)974 { 975 struct msn_data *md = soap_req->ic->proto_data; 976 969 static int msn_soap_profile_get_handle_response(struct msn_soap_req_data *soap_req) 970 { 971 struct msn_data *md = soap_req->ic->proto_data; 972 977 973 md->flags |= MSN_GOT_PROFILE; 978 msn_ns_finish_login( soap_req->ic);979 980 return MSN_SOAP_OK; 981 } 982 983 static int msn_soap_profile_get_free_data( struct msn_soap_req_data *soap_req)984 { 985 g_free( soap_req->data);974 msn_ns_finish_login(soap_req->ic); 975 976 return MSN_SOAP_OK; 977 } 978 979 static int msn_soap_profile_get_free_data(struct msn_soap_req_data *soap_req) 980 { 981 g_free(soap_req->data); 986 982 return 0; 987 983 } 988 984 989 int msn_soap_profile_get( struct im_connection *ic, const char *cid)990 { 991 return msn_soap_start( ic, g_strdup( cid),992 993 994 995 msn_soap_profile_get_free_data);985 int msn_soap_profile_get(struct im_connection *ic, const char *cid) 986 { 987 return msn_soap_start(ic, g_strdup(cid), 988 msn_soap_profile_get_build_request, 989 msn_soap_profile_get_parser, 990 msn_soap_profile_get_handle_response, 991 msn_soap_profile_get_free_data); 996 992 } 997 993 998 994 /* Update profile (display name). */ 999 static int msn_soap_profile_set_dn_build_request( struct msn_soap_req_data *soap_req)1000 { 1001 struct msn_data *md = soap_req->ic->proto_data; 1002 1003 soap_req->url = g_strdup( SOAP_STORAGE_URL);1004 soap_req->action = g_strdup( SOAP_PROFILE_SET_DN_ACTION);1005 soap_req->payload = g_markup_printf_escaped( 1006 md->tokens[3], md->profile_rid, (char*) soap_req->data);1007 995 static int msn_soap_profile_set_dn_build_request(struct msn_soap_req_data *soap_req) 996 { 997 struct msn_data *md = soap_req->ic->proto_data; 998 999 soap_req->url = g_strdup(SOAP_STORAGE_URL); 1000 soap_req->action = g_strdup(SOAP_PROFILE_SET_DN_ACTION); 1001 soap_req->payload = g_markup_printf_escaped(SOAP_PROFILE_SET_DN_PAYLOAD, 1002 md->tokens[3], md->profile_rid, (char *) soap_req->data); 1003 1008 1004 return 1; 1009 1005 } … … 1013 1009 }; 1014 1010 1015 static int msn_soap_profile_set_dn_handle_response( struct msn_soap_req_data *soap_req)1016 { 1017 return MSN_SOAP_OK; 1018 } 1019 1020 static int msn_soap_profile_set_dn_free_data( struct msn_soap_req_data *soap_req)1021 { 1022 g_free( soap_req->data);1011 static int msn_soap_profile_set_dn_handle_response(struct msn_soap_req_data *soap_req) 1012 { 1013 return MSN_SOAP_OK; 1014 } 1015 1016 static int msn_soap_profile_set_dn_free_data(struct msn_soap_req_data *soap_req) 1017 { 1018 g_free(soap_req->data); 1023 1019 return 0; 1024 1020 } 1025 1021 1026 int msn_soap_profile_set_dn( struct im_connection *ic, const char *dn)1027 { 1028 return msn_soap_start( ic, g_strdup( dn),1029 1030 1031 1032 msn_soap_profile_set_dn_free_data);1033 } 1022 int msn_soap_profile_set_dn(struct im_connection *ic, const char *dn) 1023 { 1024 return msn_soap_start(ic, g_strdup(dn), 1025 msn_soap_profile_set_dn_build_request, 1026 msn_soap_profile_set_dn_parser, 1027 msn_soap_profile_set_dn_handle_response, 1028 msn_soap_profile_set_dn_free_data); 1029 } -
protocols/msn/soap.h
raf359b4 r5ebff60 1 1 /********************************************************************\ 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * … … 43 43 44 44 45 int msn_soapq_flush( struct im_connection *ic, gboolean resend);45 int msn_soapq_flush(struct im_connection *ic, gboolean resend); 46 46 47 47 48 48 #define SOAP_HTTP_REQUEST \ 49 "POST %s HTTP/1.0\r\n" \50 "Host: %s\r\n" \51 "Accept: */*\r\n" \52 "User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \53 "Content-Type: text/xml; charset=utf-8\r\n" \54 "%s" \55 "Content-Length: %zd\r\n" \56 "Cache-Control: no-cache\r\n" \57 "\r\n" \58 "%s"49 "POST %s HTTP/1.0\r\n" \ 50 "Host: %s\r\n" \ 51 "Accept: */*\r\n" \ 52 "User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \ 53 "Content-Type: text/xml; charset=utf-8\r\n" \ 54 "%s" \ 55 "Content-Length: %zd\r\n" \ 56 "Cache-Control: no-cache\r\n" \ 57 "\r\n" \ 58 "%s" 59 59 60 60 … … 64 64 65 65 #define SOAP_PASSPORT_SSO_PAYLOAD \ 66 "<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\" " \67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 "</Envelope>"142 143 int msn_soap_passport_sso_request( struct im_connection *ic, const char *nonce);66 "<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\" " \ 67 "xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" " \ 68 "xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" " \ 69 "xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2002/12/policy\" " \ 70 "xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" " \ 71 "xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\" " \ 72 "xmlns:wssc=\"http://schemas.xmlsoap.org/ws/2004/04/sc\" " \ 73 "xmlns:wst=\"http://schemas.xmlsoap.org/ws/2004/04/trust\">" \ 74 "<Header>" \ 75 "<ps:AuthInfo " \ 76 "xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" " \ 77 "Id=\"PPAuthInfo\">" \ 78 "<ps:HostingApp>{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}</ps:HostingApp>" \ 79 "<ps:BinaryVersion>4</ps:BinaryVersion>" \ 80 "<ps:UIVersion>1</ps:UIVersion>" \ 81 "<ps:Cookies></ps:Cookies>" \ 82 "<ps:RequestParams>AQAAAAIAAABsYwQAAAAxMDMz</ps:RequestParams>" \ 83 "</ps:AuthInfo>" \ 84 "<wsse:Security>" \ 85 "<wsse:UsernameToken Id=\"user\">" \ 86 "<wsse:Username>%s</wsse:Username>" \ 87 "<wsse:Password>%s</wsse:Password>" \ 88 "</wsse:UsernameToken>" \ 89 "</wsse:Security>" \ 90 "</Header>" \ 91 "<Body>" \ 92 "<ps:RequestMultipleSecurityTokens " \ 93 "xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" " \ 94 "Id=\"RSTS\">" \ 95 "<wst:RequestSecurityToken Id=\"RST0\">" \ 96 "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \ 97 "<wsp:AppliesTo>" \ 98 "<wsa:EndpointReference>" \ 99 "<wsa:Address>http://Passport.NET/tb</wsa:Address>" \ 100 "</wsa:EndpointReference>" \ 101 "</wsp:AppliesTo>" \ 102 "</wst:RequestSecurityToken>" \ 103 "<wst:RequestSecurityToken Id=\"RST1\">" \ 104 "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \ 105 "<wsp:AppliesTo>" \ 106 "<wsa:EndpointReference>" \ 107 "<wsa:Address>messengerclear.live.com</wsa:Address>" \ 108 "</wsa:EndpointReference>" \ 109 "</wsp:AppliesTo>" \ 110 "<wsse:PolicyReference URI=\"%s\"></wsse:PolicyReference>" \ 111 "</wst:RequestSecurityToken>" \ 112 "<wst:RequestSecurityToken Id=\"RST2\">" \ 113 "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \ 114 "<wsp:AppliesTo>" \ 115 "<wsa:EndpointReference>" \ 116 "<wsa:Address>contacts.msn.com</wsa:Address>" \ 117 "</wsa:EndpointReference>" \ 118 "</wsp:AppliesTo>" \ 119 "<wsse:PolicyReference xmlns=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" URI=\"MBI\"></wsse:PolicyReference>" \ 120 "</wst:RequestSecurityToken>" \ 121 "<wst:RequestSecurityToken Id=\"RST3\">" \ 122 "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \ 123 "<wsp:AppliesTo>" \ 124 "<wsa:EndpointReference>" \ 125 "<wsa:Address>messengersecure.live.com</wsa:Address>" \ 126 "</wsa:EndpointReference>" \ 127 "</wsp:AppliesTo>" \ 128 "<wsse:PolicyReference xmlns=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" URI=\"MBI_SSL\"></wsse:PolicyReference>" \ 129 "</wst:RequestSecurityToken>" \ 130 "<wst:RequestSecurityToken Id=\"RST4\">" \ 131 "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \ 132 "<wsp:AppliesTo>" \ 133 "<wsa:EndpointReference>" \ 134 "<wsa:Address>storage.msn.com</wsa:Address>" \ 135 "</wsa:EndpointReference>" \ 136 "</wsp:AppliesTo>" \ 137 "<wsse:PolicyReference xmlns=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" URI=\"MBI_SSL\"></wsse:PolicyReference>" \ 138 "</wst:RequestSecurityToken>" \ 139 "</ps:RequestMultipleSecurityTokens>" \ 140 "</Body>" \ 141 "</Envelope>" 142 143 int msn_soap_passport_sso_request(struct im_connection *ic, const char *nonce); 144 144 145 145 146 146 #define SOAP_ABSERVICE_PAYLOAD \ 147 "<?xml version=\"1.0\" encoding=\"utf-8\"?>" \148 "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 "</soap:Envelope>"147 "<?xml version=\"1.0\" encoding=\"utf-8\"?>" \ 148 "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \ 149 "<soap:Header xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \ 150 "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ 151 "<ApplicationId xmlns=\"http://www.msn.com/webservices/AddressBook\">F6D2794D-501F-443A-ADBE-8F1490FF30FD</ApplicationId>" \ 152 "<IsMigration xmlns=\"http://www.msn.com/webservices/AddressBook\">false</IsMigration>" \ 153 "<PartnerScenario xmlns=\"http://www.msn.com/webservices/AddressBook\">%s</PartnerScenario>" \ 154 "</ABApplicationHeader>" \ 155 "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ 156 "<ManagedGroupRequest xmlns=\"http://www.msn.com/webservices/AddressBook\">false</ManagedGroupRequest>" \ 157 "<TicketToken>%s</TicketToken>" \ 158 "</ABAuthHeader>" \ 159 "</soap:Header>" \ 160 "<soap:Body xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \ 161 "%%s" \ 162 "</soap:Body>" \ 163 "</soap:Envelope>" 164 164 165 165 #define SOAP_MEMLIST_URL "http://contacts.msn.com/abservice/SharingService.asmx" … … 167 167 168 168 #define SOAP_MEMLIST_PAYLOAD \ 169 170 169 "<FindMembership xmlns=\"http://www.msn.com/webservices/AddressBook\"><serviceFilter xmlns=\"http://www.msn.com/webservices/AddressBook\"><Types xmlns=\"http://www.msn.com/webservices/AddressBook\"><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Messenger</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Invitation</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">SocialNetwork</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Space</ServiceType><ServiceType xmlns=\"http://www.msn.com/webservices/AddressBook\">Profile</ServiceType></Types></serviceFilter>" \ 170 "</FindMembership>" 171 171 172 172 #define SOAP_MEMLIST_ADD_ACTION "http://www.msn.com/webservices/AddressBook/AddMember" … … 174 174 175 175 #define SOAP_MEMLIST_EDIT_PAYLOAD \ 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 int msn_soap_memlist_request( struct im_connection *ic);197 int msn_soap_memlist_edit( struct im_connection *ic, const char *handle, gboolean add, int list);176 "<%sMember xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ 177 "<serviceHandle>" \ 178 "<Id>0</Id>" \ 179 "<Type>Messenger</Type>" \ 180 "<ForeignId></ForeignId>" \ 181 "</serviceHandle>" \ 182 "<memberships>" \ 183 "<Membership>" \ 184 "<MemberRole>%s</MemberRole>" \ 185 "<Members>" \ 186 "<Member xsi:type=\"PassportMember\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" \ 187 "<Type>Passport</Type>" \ 188 "<State>Accepted</State>" \ 189 "<PassportName>%s</PassportName>" \ 190 "</Member>" \ 191 "</Members>" \ 192 "</Membership>" \ 193 "</memberships>" \ 194 "</%sMember>" 195 196 int msn_soap_memlist_request(struct im_connection *ic); 197 int msn_soap_memlist_edit(struct im_connection *ic, const char *handle, gboolean add, int list); 198 198 199 199 … … 202 202 203 203 #define SOAP_ADDRESSBOOK_PAYLOAD \ 204 205 206 207 208 209 204 "<ABFindAll xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ 205 "<abId>00000000-0000-0000-0000-000000000000</abId>" \ 206 "<abView>Full</abView>" \ 207 "<deltasOnly>false</deltasOnly>" \ 208 "<lastChange>0001-01-01T00:00:00.0000000-08:00</lastChange>" \ 209 "</ABFindAll>" 210 210 211 211 #define SOAP_AB_NAMECHANGE_ACTION "http://www.msn.com/webservices/AddressBook/ABContactUpdate" 212 212 213 213 #define SOAP_AB_NAMECHANGE_PAYLOAD \ 214 215 216 217 218 219 220 221 222 223 224 225 214 "<ABContactUpdate xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ 215 "<abId>00000000-0000-0000-0000-000000000000</abId>" \ 216 "<contacts>" \ 217 "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ 218 "<contactInfo>" \ 219 "<contactType>Me</contactType>" \ 220 "<displayName>%s</displayName>" \ 221 "</contactInfo>" \ 222 "<propertiesChanged>DisplayName</propertiesChanged>" \ 223 "</Contact>" \ 224 "</contacts>" \ 225 "</ABContactUpdate>" 226 226 227 227 #define SOAP_AB_CONTACT_ADD_ACTION "http://www.msn.com/webservices/AddressBook/ABContactAdd" 228 228 229 229 #define SOAP_AB_CONTACT_ADD_PAYLOAD \ 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 230 "<ABContactAdd xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ 231 "<abId>00000000-0000-0000-0000-000000000000</abId>" \ 232 "<contacts>" \ 233 "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ 234 "<contactInfo>" \ 235 "<contactType>LivePending</contactType>" \ 236 "<passportName>%s</passportName>" \ 237 "<isMessengerUser>true</isMessengerUser>" \ 238 "<MessengerMemberInfo>" \ 239 "<DisplayName>%s</DisplayName>" \ 240 "</MessengerMemberInfo>" \ 241 "</contactInfo>" \ 242 "</Contact>" \ 243 "</contacts>" \ 244 "<options>" \ 245 "<EnableAllowListManagement>true</EnableAllowListManagement>" \ 246 "</options>" \ 247 "</ABContactAdd>" 248 248 249 249 #define SOAP_AB_CONTACT_DEL_ACTION "http://www.msn.com/webservices/AddressBook/ABContactDelete" 250 250 251 251 #define SOAP_AB_CONTACT_DEL_PAYLOAD \ 252 253 254 255 256 257 258 259 260 261 int msn_soap_addressbook_request( struct im_connection *ic);262 int msn_soap_addressbook_set_display_name( struct im_connection *ic, const char *new);263 int msn_soap_ab_contact_add( struct im_connection *ic, bee_user_t *bu);264 int msn_soap_ab_contact_del( struct im_connection *ic, bee_user_t *bu);252 "<ABContactDelete xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ 253 "<abId>00000000-0000-0000-0000-000000000000</abId>" \ 254 "<contacts>" \ 255 "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ 256 "<contactId>%s</contactId>" \ 257 "</Contact>" \ 258 "</contacts>" \ 259 "</ABContactDelete>" 260 261 int msn_soap_addressbook_request(struct im_connection *ic); 262 int msn_soap_addressbook_set_display_name(struct im_connection *ic, const char *new); 263 int msn_soap_ab_contact_add(struct im_connection *ic, bee_user_t *bu); 264 int msn_soap_ab_contact_del(struct im_connection *ic, bee_user_t *bu); 265 265 266 266 … … 270 270 271 271 #define SOAP_PROFILE_GET_PAYLOAD \ 272 "<?xml version=\"1.0\" encoding=\"utf-8\"?>" \273 "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 "</soap:Envelope>"272 "<?xml version=\"1.0\" encoding=\"utf-8\"?>" \ 273 "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \ 274 "<soap:Header xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \ 275 "<StorageApplicationHeader xmlns=\"http://www.msn.com/webservices/storage/w10\">" \ 276 "<ApplicationID>Messenger Client 9.0</ApplicationID>" \ 277 "<Scenario>Initial</Scenario>" \ 278 "</StorageApplicationHeader>" \ 279 "<StorageUserHeader xmlns=\"http://www.msn.com/webservices/storage/w10\">" \ 280 "<Puid>0</Puid>" \ 281 "<TicketToken>%s</TicketToken>" \ 282 "</StorageUserHeader>" \ 283 "</soap:Header>" \ 284 "<soap:Body xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \ 285 "<GetProfile xmlns=\"http://www.msn.com/webservices/storage/w10\">" \ 286 "<profileHandle>" \ 287 "<Alias>" \ 288 "<Name>%s</Name>" \ 289 "<NameSpace>MyCidStuff</NameSpace>" \ 290 "</Alias>" \ 291 "<RelationshipName>MyProfile</RelationshipName>" \ 292 "</profileHandle>" \ 293 "<profileAttributes>" \ 294 "<ResourceID>true</ResourceID>" \ 295 "<DateModified>true</DateModified>" \ 296 "<ExpressionProfileAttributes>" \ 297 "<ResourceID>true</ResourceID>" \ 298 "<DateModified>true</DateModified>" \ 299 "<DisplayName>true</DisplayName>" \ 300 "<DisplayNameLastModified>true</DisplayNameLastModified>" \ 301 "<PersonalStatus>true</PersonalStatus>" \ 302 "<PersonalStatusLastModified>true</PersonalStatusLastModified>" \ 303 "<StaticUserTilePublicURL>true</StaticUserTilePublicURL>" \ 304 "<Photo>true</Photo>" \ 305 "<Flags>true</Flags>" \ 306 "</ExpressionProfileAttributes>" \ 307 "</profileAttributes>" \ 308 "</GetProfile>" \ 309 "</soap:Body>" \ 310 "</soap:Envelope>" 311 311 312 312 #define SOAP_PROFILE_SET_DN_PAYLOAD \ 313 "<?xml version=\"1.0\" encoding=\"utf-8\"?>" \314 "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 "</soap:Envelope>"338 339 int msn_soap_profile_get( struct im_connection *ic, const char *cid);340 int msn_soap_profile_set_dn( struct im_connection *ic, const char *dn);313 "<?xml version=\"1.0\" encoding=\"utf-8\"?>" \ 314 "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \ 315 "<soap:Header xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \ 316 "<StorageApplicationHeader xmlns=\"http://www.msn.com/webservices/storage/w10\">" \ 317 "<ApplicationID>Messenger Client 9.0</ApplicationID>" \ 318 "<Scenario>Initial</Scenario>" \ 319 "</StorageApplicationHeader>" \ 320 "<StorageUserHeader xmlns=\"http://www.msn.com/webservices/storage/w10\">" \ 321 "<Puid>0</Puid>" \ 322 "<TicketToken>%s</TicketToken>" \ 323 "</StorageUserHeader>" \ 324 "</soap:Header>" \ 325 "<soap:Body xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \ 326 "<UpdateProfile xmlns=\"http://www.msn.com/webservices/storage/w10\">" \ 327 "<profile>" \ 328 "<ResourceID>%s</ResourceID>" \ 329 "<ExpressionProfile>" \ 330 "<FreeText>Update</FreeText>" \ 331 "<DisplayName>%s</DisplayName>" \ 332 "<Flags>0</Flags>" \ 333 "</ExpressionProfile>" \ 334 "</profile>" \ 335 "</UpdateProfile>" \ 336 "</soap:Body>" \ 337 "</soap:Envelope>" 338 339 int msn_soap_profile_get(struct im_connection *ic, const char *cid); 340 int msn_soap_profile_set_dn(struct im_connection *ic, const char *dn); 341 341 342 342 #endif /* __SOAP_H__ */ -
protocols/msn/tables.c
raf359b4 r5ebff60 1 1 /********************************************************************\ 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * … … 40 40 }; 41 41 42 const struct msn_away_state *msn_away_state_by_code( char *code)42 const struct msn_away_state *msn_away_state_by_code(char *code) 43 43 { 44 44 int i; 45 46 for( i = 0; *msn_away_state_list[i].code; i ++ ) 47 if( g_strcasecmp( msn_away_state_list[i].code, code ) == 0 ) 48 return( msn_away_state_list + i ); 49 45 46 for (i = 0; *msn_away_state_list[i].code; i++) { 47 if (g_strcasecmp(msn_away_state_list[i].code, code) == 0) { 48 return(msn_away_state_list + i); 49 } 50 } 51 50 52 return NULL; 51 53 } 52 54 53 const struct msn_away_state *msn_away_state_by_name( char *name)55 const struct msn_away_state *msn_away_state_by_name(char *name) 54 56 { 55 57 int i; 56 57 for( i = 0; *msn_away_state_list[i].code; i ++ ) 58 if( g_strcasecmp( msn_away_state_list[i].name, name ) == 0 ) 59 return( msn_away_state_list + i ); 60 58 59 for (i = 0; *msn_away_state_list[i].code; i++) { 60 if (g_strcasecmp(msn_away_state_list[i].name, name) == 0) { 61 return(msn_away_state_list + i); 62 } 63 } 64 61 65 return NULL; 62 66 } … … 87 91 { 280, "Switchboard failed", STATUS_SB_FATAL }, 88 92 { 281, "Transfer to switchboard failed", 0 }, 89 93 90 94 { 300, "Required field missing", 0 }, 91 95 { 302, "Not logged in", 0 }, 92 96 93 97 { 500, "Internal server error/Account banned", STATUS_FATAL }, 94 98 { 501, "Database server error", STATUS_FATAL }, … … 97 101 { 520, "Memory allocation failed", STATUS_FATAL }, 98 102 { 540, "Challenge response invalid", STATUS_FATAL }, 99 103 100 104 { 600, "Server is busy", STATUS_FATAL }, 101 105 { 601, "Server is unavailable", STATUS_FATAL }, … … 104 108 { 604, "Server is going down", STATUS_FATAL }, 105 109 { 605, "Server is unavailable", STATUS_FATAL }, 106 110 107 111 { 700, "Could not create connection", STATUS_FATAL }, 108 112 { 710, "Invalid CVR parameters", STATUS_FATAL }, … … 114 118 { 717, "Bad friend file", STATUS_FATAL }, 115 119 { 731, "Not expected/Invalid argument", 0 }, 116 120 117 121 { 800, "Changing too rapidly", 0 }, 118 122 119 123 { 910, "Server is busy", STATUS_FATAL }, 120 124 { 911, "Authentication failed", STATUS_SB_FATAL | STATUS_FATAL }, … … 135 139 }; 136 140 137 const struct msn_status_code *msn_status_by_number( int number)141 const struct msn_status_code *msn_status_by_number(int number) 138 142 { 139 143 static struct msn_status_code *unknown = NULL; 140 144 int i; 141 142 for( i = 0; msn_status_code_list[i].number >= 0; i ++ ) 143 if( msn_status_code_list[i].number == number ) 144 return( msn_status_code_list + i ); 145 146 if( unknown == NULL ) 147 { 148 unknown = g_new0( struct msn_status_code, 1 ); 149 unknown->text = g_new0( char, 128 ); 145 146 for (i = 0; msn_status_code_list[i].number >= 0; i++) { 147 if (msn_status_code_list[i].number == number) { 148 return(msn_status_code_list + i); 149 } 150 150 } 151 151 152 if (unknown == NULL) { 153 unknown = g_new0(struct msn_status_code, 1); 154 unknown->text = g_new0(char, 128); 155 } 156 152 157 unknown->number = number; 153 158 unknown->flags = 0; 154 g_snprintf( unknown->text, 128, "Unknown error (%d)", number);155 156 return( unknown);159 g_snprintf(unknown->text, 128, "Unknown error (%d)", number); 160 161 return(unknown); 157 162 }
Note: See TracChangeset
for help on using the changeset viewer.