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 &n