comparison src/protocols/simple/simple.c @ 13200:33bef17125c2

[gaim-migrate @ 15563] This is the soon-to-be-infamous nonblocking network activity patch that I've been working on. Feel free to yell at me if this makes you unhappy. committer: Tailor Script <tailor@pidgin.im>
author Daniel Atallah <daniel.atallah@gmail.com>
date Thu, 09 Feb 2006 04:17:56 +0000
parents 2d68ea9616b3
children 0bfc9b72b9ce
comparison
equal deleted inserted replaced
13199:d8f238864c88 13200:33bef17125c2
67 67
68 static void simple_keep_alive(GaimConnection *gc) { 68 static void simple_keep_alive(GaimConnection *gc) {
69 struct simple_account_data *sip = gc->proto_data; 69 struct simple_account_data *sip = gc->proto_data;
70 if(sip->udp) { /* in case of UDP send a packet only with a 0 byte to 70 if(sip->udp) { /* in case of UDP send a packet only with a 0 byte to
71 remain in the NAT table */ 71 remain in the NAT table */
72 gchar buf[2]={0,0}; 72 gchar buf[2] = {0, 0};
73 gaim_debug_info("simple", "sending keep alive\n"); 73 gaim_debug_info("simple", "sending keep alive\n");
74 sendto(sip->fd, buf, 1, 0, (struct sockaddr*)&sip->serveraddr, sizeof(struct sockaddr_in)); 74 sendto(sip->fd, buf, 1, 0, (struct sockaddr*)&sip->serveraddr, sizeof(struct sockaddr_in));
75 } 75 }
76 return; 76 return;
77 } 77 }
161 g_free(watcher->dialog.theirtag); 161 g_free(watcher->dialog.theirtag);
162 g_free(watcher); 162 g_free(watcher);
163 } 163 }
164 164
165 static struct sip_connection *connection_create(struct simple_account_data *sip, int fd) { 165 static struct sip_connection *connection_create(struct simple_account_data *sip, int fd) {
166 struct sip_connection *ret = g_new0(struct sip_connection,1); 166 struct sip_connection *ret = g_new0(struct sip_connection, 1);
167 ret->fd = fd; 167 ret->fd = fd;
168 sip->openconns = g_slist_append(sip->openconns, ret); 168 sip->openconns = g_slist_append(sip->openconns, ret);
169 return ret; 169 return ret;
170 } 170 }
171 171
189 189
190 static void simple_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group) 190 static void simple_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group)
191 { 191 {
192 struct simple_account_data *sip = (struct simple_account_data *)gc->proto_data; 192 struct simple_account_data *sip = (struct simple_account_data *)gc->proto_data;
193 struct simple_buddy *b; 193 struct simple_buddy *b;
194 if(strncmp("sip:", buddy->name,4)) { 194 if(strncmp("sip:", buddy->name, 4)) {
195 gchar *buf = g_strdup_printf("sip:%s",buddy->name); 195 gchar *buf = g_strdup_printf("sip:%s", buddy->name);
196 gaim_blist_rename_buddy(buddy, buf); 196 gaim_blist_rename_buddy(buddy, buf);
197 g_free(buf); 197 g_free(buf);
198 } 198 }
199 if(!g_hash_table_lookup(sip->buddies, buddy->name)) { 199 if(!g_hash_table_lookup(sip->buddies, buddy->name)) {
200 b = g_new0(struct simple_buddy, 1); 200 b = g_new0(struct simple_buddy, 1);
201 gaim_debug_info("simple","simple_add_buddy %s\n",buddy->name); 201 gaim_debug_info("simple", "simple_add_buddy %s\n", buddy->name);
202 b->name = g_strdup(buddy->name); 202 b->name = g_strdup(buddy->name);
203 g_hash_table_insert(sip->buddies, b->name, b); 203 g_hash_table_insert(sip->buddies, b->name, b);
204 } else { 204 } else {
205 gaim_debug_info("simple","buddy %s already in internal list\n", buddy->name); 205 gaim_debug_info("simple", "buddy %s already in internal list\n", buddy->name);
206 } 206 }
207 } 207 }
208 208
209 static void simple_get_buddies(GaimConnection *gc) { 209 static void simple_get_buddies(GaimConnection *gc) {
210 GaimBlistNode *gnode, *cnode, *bnode; 210 GaimBlistNode *gnode, *cnode, *bnode;
211 211
212 gaim_debug_info("simple","simple_get_buddies\n"); 212 gaim_debug_info("simple", "simple_get_buddies\n");
213 213
214 for(gnode = gaim_get_blist()->root; gnode; gnode = gnode->next) { 214 for(gnode = gaim_get_blist()->root; gnode; gnode = gnode->next) {
215 if(!GAIM_BLIST_NODE_IS_GROUP(gnode)) continue; 215 if(!GAIM_BLIST_NODE_IS_GROUP(gnode)) continue;
216 for(cnode = gnode->child; cnode; cnode = cnode->next) { 216 for(cnode = gnode->child; cnode; cnode = cnode->next) {
217 if(!GAIM_BLIST_NODE_IS_CONTACT(cnode)) continue; 217 if(!GAIM_BLIST_NODE_IS_CONTACT(cnode)) continue;
248 types = g_list_append(types, type); 248 types = g_list_append(types, type);
249 249
250 return types; 250 return types;
251 } 251 }
252 252
253 static gchar *auth_header(struct simple_account_data *sip, struct sip_auth *auth, gchar *method, gchar *target) { 253 static gchar *auth_header(struct simple_account_data *sip,
254 struct sip_auth *auth, const gchar *method, const gchar *target) {
254 gchar noncecount[9]; 255 gchar noncecount[9];
255 gchar *response; 256 gchar *response;
256 gchar *ret; 257 gchar *ret;
257 gchar *tmp; 258 gchar *tmp;
258 const char *authdomain; 259 const char *authdomain;
259 const char *authuser; 260 const char *authuser;
260 261
261 authdomain = gaim_account_get_string(sip->account, "authdomain", ""); 262 authdomain = gaim_account_get_string(sip->account, "authdomain", "");
262 authuser = gaim_account_get_string(sip->account, "authuser", sip->username); 263 authuser = gaim_account_get_string(sip->account, "authuser", sip->username);
263 264
264 if(!authuser || strlen(authuser)<1) { 265 if(!authuser || strlen(authuser) < 1) {
265 authuser = sip->username; 266 authuser = sip->username;
266 } 267 }
267 268
268 if(auth->type == 1) { /* Digest */ 269 if(auth->type == 1) { /* Digest */
269 sprintf(noncecount, "%08d", auth->nc++); 270 sprintf(noncecount, "%08d", auth->nc++);
295 ret = g_strdup_printf("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", nc=\"%s\", response=\"%s\"\r\n", authuser, auth->realm, auth->nonce, target, noncecount, response); 296 ret = g_strdup_printf("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", nc=\"%s\", response=\"%s\"\r\n", authuser, auth->realm, auth->nonce, target, noncecount, response);
296 g_free(response); 297 g_free(response);
297 return ret; 298 return ret;
298 } 299 }
299 300
300 static char * parse_attribute(const char *attrname, char *source) { 301 static char *parse_attribute(const char *attrname, char *source) {
301 char *tmp, *tmp2, *retval = NULL; 302 char *tmp, *tmp2, *retval = NULL;
302 int len = strlen(attrname); 303 int len = strlen(attrname);
303 304
304 if(!strncmp(source, attrname, len)) { 305 if(!strncmp(source, attrname, len)) {
305 tmp = source + len; 306 tmp = source + len;
312 313
313 return retval; 314 return retval;
314 } 315 }
315 316
316 static void fill_auth(struct simple_account_data *sip, gchar *hdr, struct sip_auth *auth) { 317 static void fill_auth(struct simple_account_data *sip, gchar *hdr, struct sip_auth *auth) {
317 int i=0; 318 int i = 0;
318 const char *authuser; 319 const char *authuser;
319 char *tmp; 320 char *tmp;
320 gchar **parts; 321 gchar **parts;
321 322
322 authuser = gaim_account_get_string(sip->account, "authuser", sip->username); 323 authuser = gaim_account_get_string(sip->account, "authuser", sip->username);
323 324
324 if(!authuser || strlen(authuser)<1) { 325 if(!authuser || strlen(authuser) < 1) {
325 authuser = sip->username; 326 authuser = sip->username;
326 } 327 }
327 328
328 if(!hdr) { 329 if(!hdr) {
329 gaim_debug_error("simple", "fill_auth: hdr==NULL\n"); 330 gaim_debug_error("simple", "fill_auth: hdr==NULL\n");
332 333
333 if(!g_strncasecmp(hdr, "NTLM", 4)) { 334 if(!g_strncasecmp(hdr, "NTLM", 4)) {
334 gaim_debug_info("simple", "found NTLM\n"); 335 gaim_debug_info("simple", "found NTLM\n");
335 auth->type = 2; 336 auth->type = 2;
336 if(!strstr(hdr, "gssapi-data")) { 337 if(!strstr(hdr, "gssapi-data")) {
337 gaim_debug_info("simple","here"); 338 gaim_debug_info("simple", "here");
338 parts = g_strsplit(hdr+5, "\", ", 0); 339 parts = g_strsplit(hdr+5, "\", ", 0);
339 i = 0; 340 i = 0;
340 while(parts[i]) { 341 while(parts[i]) {
341 gaim_debug_info("simple","parts[i] %s\n",parts[i]); 342 gaim_debug_info("simple", "parts[i] %s\n", parts[i]);
342 if((tmp = parse_attribute("targetname=\"", 343 if((tmp = parse_attribute("targetname=\"",
343 parts[i]))) { 344 parts[i]))) {
344 auth->target = tmp; 345 auth->target = tmp;
345 } 346 }
346 else if((tmp = parse_attribute("realm=\"", 347 else if((tmp = parse_attribute("realm=\"",
386 gaim_debug(GAIM_DEBUG_MISC, "simple", "nonce: %s realm: %s ", auth->nonce ? auth->nonce : "(null)", auth->realm ? auth->realm : "(null)"); 387 gaim_debug(GAIM_DEBUG_MISC, "simple", "nonce: %s realm: %s ", auth->nonce ? auth->nonce : "(null)", auth->realm ? auth->realm : "(null)");
387 388
388 auth->digest_session_key = gaim_cipher_http_digest_calculate_session_key( 389 auth->digest_session_key = gaim_cipher_http_digest_calculate_session_key(
389 "md5", authuser, auth->realm, sip->password, auth->nonce, NULL); 390 "md5", authuser, auth->realm, sip->password, auth->nonce, NULL);
390 391
391 auth->nc=1; 392 auth->nc = 1;
393 }
394
395 static void simple_canwrite_cb(gpointer data, gint source, GaimInputCondition cond) {
396 GaimConnection *gc = data;
397 struct simple_account_data *sip = gc->proto_data;
398 gsize max_write;
399 gssize written;
400
401 max_write = gaim_circ_buffer_get_max_read(sip->txbuf);
402
403 if(max_write == 0) {
404 gaim_input_remove(sip->tx_handler);
405 sip->tx_handler = 0;
406 return;
407 }
408
409 written = write(sip->fd, sip->txbuf->outptr, max_write);
410
411 if(written < 0 && errno == EAGAIN)
412 written = 0;
413 else if(written <= 0) {
414 /*TODO: do we really want to disconnect on a failure to write?*/
415 gaim_connection_error(gc, _("Could not write"));
416 return;
417 }
418
419 gaim_circ_buffer_mark_read(sip->txbuf, written);
392 } 420 }
393 421
394 static void simple_input_cb(gpointer data, gint source, GaimInputCondition cond); 422 static void simple_input_cb(gpointer data, gint source, GaimInputCondition cond);
395 423
396 static void send_later_cb(gpointer data, gint source, GaimInputCondition cond) { 424 static void send_later_cb(gpointer data, gint source, GaimInputCondition cond) {
397 GaimConnection *gc = data; 425 GaimConnection *gc = data;
398 struct simple_account_data *sip = gc->proto_data; 426 struct simple_account_data *sip = gc->proto_data;
399 struct sip_connection *conn; 427 struct sip_connection *conn;
400 428
401 if( source < 0 ) { 429 if(source < 0) {
402 gaim_connection_error(gc,"Could not connect"); 430 gaim_connection_error(gc, _("Could not connect"));
403 return; 431 return;
404 } 432 }
405 433
406 sip->fd = source; 434 sip->fd = source;
407 sip->connecting = FALSE; 435 sip->connecting = FALSE;
408 write(sip->fd, sip->sendlater, strlen(sip->sendlater)); 436
437 simple_canwrite_cb(gc, sip->fd, GAIM_INPUT_WRITE);
438
439 /* If there is more to write now, we need to register a handler */
440 if(sip->txbuf->bufused > 0)
441 sip->tx_handler = gaim_input_add(sip->fd, GAIM_INPUT_WRITE,
442 simple_canwrite_cb, gc);
443
409 conn = connection_create(sip, source); 444 conn = connection_create(sip, source);
410 conn->inputhandler = gaim_input_add(sip->fd, GAIM_INPUT_READ, simple_input_cb, gc); 445 conn->inputhandler = gaim_input_add(sip->fd, GAIM_INPUT_READ, simple_input_cb, gc);
411 g_free(sip->sendlater);
412 sip->sendlater = NULL;
413 } 446 }
414 447
415 448
416 static void sendlater(GaimConnection *gc, const char *buf) { 449 static void sendlater(GaimConnection *gc, const char *buf) {
417 struct simple_account_data *sip = gc->proto_data; 450 struct simple_account_data *sip = gc->proto_data;
418 int error = 0; 451 int error = 0;
419 if(!sip->connecting) { 452 if(!sip->connecting) {
420 gaim_debug_info("simple","connecting to %s port %d\n", sip->realhostname ? sip->realhostname : "{NULL}", sip->realport); 453 gaim_debug_info("simple", "connecting to %s port %d\n", sip->realhostname ? sip->realhostname : "{NULL}", sip->realport);
421 error = gaim_proxy_connect(sip->account, sip->realhostname, sip->realport, send_later_cb, gc); 454 error = gaim_proxy_connect(sip->account, sip->realhostname, sip->realport, send_later_cb, gc);
422 if(error) { 455 if(error) {
423 gaim_connection_error(gc, _("Couldn't create socket")); 456 gaim_connection_error(gc, _("Couldn't create socket"));
424 } 457 }
425 sip->connecting = TRUE; 458 sip->connecting = TRUE;
426 } 459 }
427 if(sip->sendlater) { 460
428 gchar *old = sip->sendlater; 461 if(gaim_circ_buffer_get_max_read(sip->txbuf) > 0)
429 sip->sendlater = g_strdup_printf("%s\r\n%s",old, buf); 462 gaim_circ_buffer_append(sip->txbuf, "\r\n", 2);
430 g_free(old); 463
431 } else { 464 gaim_circ_buffer_append(sip->txbuf, buf, strlen(buf));
432 sip->sendlater = g_strdup(buf); 465 }
433 } 466
434 } 467 static void sendout_pkt(GaimConnection *gc, const char *buf) {
435
436 static int sendout_pkt(GaimConnection *gc, const char *buf) {
437 struct simple_account_data *sip = gc->proto_data; 468 struct simple_account_data *sip = gc->proto_data;
438 time_t currtime = time(NULL); 469 time_t currtime = time(NULL);
439 int ret = 0; 470 int writelen = strlen(buf);
440 471
441 gaim_debug(GAIM_DEBUG_MISC, "simple", "\n\nsending - %s\n######\n%s\n######\n\n", ctime(&currtime), buf); 472 gaim_debug(GAIM_DEBUG_MISC, "simple", "\n\nsending - %s\n######\n%s\n######\n\n", ctime(&currtime), buf);
442 if(sip->udp) { 473 if(sip->udp) {
443 if(sendto(sip->fd, buf, strlen(buf), 0, (struct sockaddr*)&sip->serveraddr, sizeof(struct sockaddr_in)) < strlen(buf)) { 474 if(sendto(sip->fd, buf, writelen, 0, (struct sockaddr*)&sip->serveraddr, sizeof(struct sockaddr_in)) < writelen) {
444 gaim_debug_info("simple", "could not send packet\n"); 475 gaim_debug_info("simple", "could not send packet\n");
445 } 476 }
446 } else { 477 } else {
447 if(sip->fd <0 ) { 478 int ret;
479 if(sip->fd < 0) {
448 sendlater(gc, buf); 480 sendlater(gc, buf);
449 return 0; 481 return;
450 } 482 }
451 ret = write(sip->fd, buf, strlen(buf)); 483
452 if(ret < 0) { 484 if(sip->tx_handler) {
453 sendlater(gc,buf); 485 ret = -1;
454 return 0; 486 errno = EAGAIN;
455 } 487 } else
456 } 488 ret = write(sip->fd, buf, writelen);
457 return ret; 489
490 if (ret < 0 && errno == EAGAIN)
491 ret = 0;
492 else if(ret <= 0) { /* XXX: When does this happen legitimately? */
493 sendlater(gc, buf);
494 return;
495 }
496
497 if (ret < writelen) {
498 if(!sip->tx_handler)
499 sip->tx_handler = gaim_input_add(sip->fd,
500 GAIM_INPUT_WRITE, simple_canwrite_cb,
501 gc);
502
503 /* XXX: is it OK to do this? You might get part of a request sent
504 with part of another. */
505 if(sip->txbuf->bufused > 0)
506 gaim_circ_buffer_append(sip->txbuf, "\r\n", 2);
507
508 gaim_circ_buffer_append(sip->txbuf, buf + ret,
509 writelen - ret);
510 }
511 }
458 } 512 }
459 513
460 static void sendout_sipmsg(struct simple_account_data *sip, struct sipmsg *msg) { 514 static void sendout_sipmsg(struct simple_account_data *sip, struct sipmsg *msg) {
461 GSList *tmp = msg->headers; 515 GSList *tmp = msg->headers;
462 gchar *name; 516 gchar *name;
485 correct content length */ 539 correct content length */
486 sipmsg_remove_header(msg, "Content-Length"); 540 sipmsg_remove_header(msg, "Content-Length");
487 if(body) { 541 if(body) {
488 gchar len[12]; 542 gchar len[12];
489 sprintf(len, "%" G_GSIZE_FORMAT , strlen(body)); 543 sprintf(len, "%" G_GSIZE_FORMAT , strlen(body));
490 sipmsg_add_header(msg, "Content-Length",len); 544 sipmsg_add_header(msg, "Content-Length", len);
491 } 545 }
492 else 546 else
493 sipmsg_add_header(msg, "Content-Length", "0"); 547 sipmsg_add_header(msg, "Content-Length", "0");
494 g_string_append_printf(outstr, "SIP/2.0 %d %s\r\n", code, text); 548 g_string_append_printf(outstr, "SIP/2.0 %d %s\r\n", code, text);
495 while(tmp) { 549 while(tmp) {
530 return trans; 584 return trans;
531 } 585 }
532 transactions = transactions->next; 586 transactions = transactions->next;
533 } 587 }
534 588
535 return (struct transaction *)NULL; 589 return NULL;
536 } 590 }
537 591
538 static void send_sip_request(GaimConnection *gc, gchar *method, gchar *url, gchar *to, gchar *addheaders, gchar *body, struct sip_dialog *dialog, TransCallback tc) { 592 static void send_sip_request(GaimConnection *gc, const gchar *method,
593 const gchar *url, const gchar *to, const gchar *addheaders,
594 const gchar *body, struct sip_dialog *dialog, TransCallback tc) {
539 struct simple_account_data *sip = gc->proto_data; 595 struct simple_account_data *sip = gc->proto_data;
540 char *callid = dialog ? g_strdup(dialog->callid) : gencallid(); 596 char *callid = dialog ? g_strdup(dialog->callid) : gencallid();
541 char *auth = ""; 597 char *auth = "";
542 char *addh = ""; 598 const char *addh = "";
543 gchar *branch = genbranch(); 599 gchar *branch = genbranch();
544 char *buf; 600 char *buf;
545 601
546 if(!strcmp(method,"REGISTER")) { 602 if(!strcmp(method, "REGISTER")) {
547 if(sip->regcallid) { 603 if(sip->regcallid) {
548 g_free(callid); 604 g_free(callid);
549 callid = g_strdup(sip->regcallid); 605 callid = g_strdup(sip->regcallid);
550 } 606 }
551 else sip->regcallid = g_strdup(callid); 607 else sip->regcallid = g_strdup(callid);
552 } 608 }
553 609
554 if(addheaders) addh = addheaders; 610 if(addheaders) addh = addheaders;
555 if(sip->registrar.type && !strcmp(method,"REGISTER")) { 611 if(sip->registrar.type && !strcmp(method, "REGISTER")) {
556 buf = auth_header(sip, &sip->registrar, method, url); 612 buf = auth_header(sip, &sip->registrar, method, url);
557 auth = g_strdup_printf("Authorization: %s", buf); 613 auth = g_strdup_printf("Authorization: %s", buf);
558 g_free(buf); 614 g_free(buf);
559 gaim_debug(GAIM_DEBUG_MISC, "simple", "header %s", auth); 615 gaim_debug(GAIM_DEBUG_MISC, "simple", "header %s", auth);
560 } 616 }
561 617
562 if(sip->proxy.type && strcmp(method,"REGISTER")) { 618 if(sip->proxy.type && strcmp(method, "REGISTER")) {
563 buf = auth_header(sip, &sip->proxy, method, url); 619 buf = auth_header(sip, &sip->proxy, method, url);
564 auth = g_strdup_printf("Proxy-Authorization: %s", buf); 620 auth = g_strdup_printf("Proxy-Authorization: %s", buf);
565 g_free(buf); 621 g_free(buf);
566 gaim_debug(GAIM_DEBUG_MISC, "simple", "header %s", auth); 622 gaim_debug(GAIM_DEBUG_MISC, "simple", "header %s", auth);
567 } 623 }
601 657
602 /* add to ongoing transactions */ 658 /* add to ongoing transactions */
603 659
604 transactions_add_buf(sip, buf, tc); 660 transactions_add_buf(sip, buf, tc);
605 661
606 sendout_pkt(gc,buf); 662 sendout_pkt(gc, buf);
607 663
608 g_free(buf); 664 g_free(buf);
609 } 665 }
610 666
611 static char *get_contact(struct simple_account_data *sip) { 667 static char *get_contact(struct simple_account_data *sip) {
612 return g_strdup_printf("<sip:%s@%s:%d;transport=%s>;methods=\"MESSAGE, SUBSCRIBE, NOTIFY\"", sip->username, gaim_network_get_my_ip(-1), sip->listenport, sip->udp ? "udp" : "tcp"); 668 return g_strdup_printf("<sip:%s@%s:%d;transport=%s>;methods=\"MESSAGE, SUBSCRIBE, NOTIFY\"", sip->username, gaim_network_get_my_ip(-1), sip->listenport, sip->udp ? "udp" : "tcp");
613 } 669 }
614 670
615 static void do_register_exp(struct simple_account_data *sip, int expire) { 671 static void do_register_exp(struct simple_account_data *sip, int expire) {
616 char *uri = g_strdup_printf("sip:%s",sip->servername); 672 char *uri = g_strdup_printf("sip:%s", sip->servername);
617 char *to = g_strdup_printf("sip:%s@%s",sip->username,sip->servername); 673 char *to = g_strdup_printf("sip:%s@%s", sip->username, sip->servername);
618 char *contact = get_contact(sip); 674 char *contact = get_contact(sip);
619 char *hdr = g_strdup_printf("Contact: %s\r\nExpires: %d\r\n", contact, expire); 675 char *hdr = g_strdup_printf("Contact: %s\r\nExpires: %d\r\n", contact, expire);
620 g_free(contact); 676 g_free(contact);
621 677
622 sip->registerstatus = 1; 678 sip->registerstatus = 1;
624 if(expire) { 680 if(expire) {
625 sip->reregister = time(NULL) + expire - 50; 681 sip->reregister = time(NULL) + expire - 50;
626 } else { 682 } else {
627 sip->reregister = time(NULL) + 600; 683 sip->reregister = time(NULL) + 600;
628 } 684 }
629 send_sip_request(sip->gc,"REGISTER",uri,to, hdr, "", NULL, process_register_response); 685
686 send_sip_request(sip->gc, "REGISTER", uri, to, hdr, "", NULL,
687 process_register_response);
688
630 g_free(hdr); 689 g_free(hdr);
631 g_free(uri); 690 g_free(uri);
632 g_free(to); 691 g_free(to);
633 } 692 }
634 693
639 static gchar *parse_from(gchar *hdr) { 698 static gchar *parse_from(gchar *hdr) {
640 gchar *from = hdr; 699 gchar *from = hdr;
641 gchar *tmp; 700 gchar *tmp;
642 701
643 if(!from) return NULL; 702 if(!from) return NULL;
644 gaim_debug_info("simple", "parsing address out of %s\n",from); 703 gaim_debug_info("simple", "parsing address out of %s\n", from);
645 tmp = strchr(from, '<'); 704 tmp = strchr(from, '<');
646 705
647 /* i hate the different SIP UA behaviours... */ 706 /* i hate the different SIP UA behaviours... */
648 if(tmp) { /* sip address in <...> */ 707 if(tmp) { /* sip address in <...> */
649 from = tmp+1; 708 from = tmp+1;
650 tmp = strchr(from,'>'); 709 tmp = strchr(from, '>');
651 if(tmp) { 710 if(tmp) {
652 from = g_strndup(from,tmp-from); 711 from = g_strndup(from, tmp-from);
653 } else { 712 } else {
654 gaim_debug_info("simple", "found < without > in From\n"); 713 gaim_debug_info("simple", "found < without > in From\n");
655 return NULL; 714 return NULL;
656 } 715 }
657 } else { 716 } else {
658 tmp = strchr(from, ';'); 717 tmp = strchr(from, ';');
659 if(tmp) { 718 if(tmp) {
660 from = g_strndup(from,tmp-from); 719 from = g_strndup(from, tmp-from);
661 } else { 720 } else {
662 from = g_strdup(from); 721 from = g_strdup(from);
663 } 722 }
664 } 723 }
665 gaim_debug_info("simple", "got %s\n",from); 724 gaim_debug_info("simple", "got %s\n", from);
666 return from; 725 return from;
667 } 726 }
668 727
669 static gboolean process_subscribe_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { 728 static gboolean process_subscribe_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) {
670 gchar *to = parse_from(sipmsg_find_header(tc->msg,"To")); /* cant be NULL since it is our own msg */ 729 gchar *to = parse_from(sipmsg_find_header(tc->msg, "To")); /* cant be NULL since it is our own msg */
671 730
672 if(msg->response==200 || msg->response==202) { 731 if(msg->response == 200 || msg->response == 202) {
673 return TRUE; 732 return TRUE;
674 } 733 }
675 734
676 /* we can not subscribe -> user is offline (TODO unknown status?) */ 735 /* we can not subscribe -> user is offline (TODO unknown status?) */
677 736
682 741
683 static void simple_subscribe(struct simple_account_data *sip, struct simple_buddy *buddy) { 742 static void simple_subscribe(struct simple_account_data *sip, struct simple_buddy *buddy) {
684 gchar *contact = "Expires: 300\r\nAccept: application/pidf+xml, application/xpidf+xml\r\nEvent: presence\r\n"; 743 gchar *contact = "Expires: 300\r\nAccept: application/pidf+xml, application/xpidf+xml\r\nEvent: presence\r\n";
685 gchar *to; 744 gchar *to;
686 gchar *tmp; 745 gchar *tmp;
687 if(strstr(buddy->name,"sip:")) to = g_strdup(buddy->name); 746
688 else to = g_strdup_printf("sip:%s",buddy->name); 747 if(strstr(buddy->name,"sip:"))
748 to = g_strdup(buddy->name);
749 else
750 to = g_strdup_printf("sip:%s", buddy->name);
751
689 tmp = get_contact(sip); 752 tmp = get_contact(sip);
690 contact = g_strdup_printf("%sContact: %s\r\n", contact, tmp); 753 contact = g_strdup_printf("%sContact: %s\r\n", contact, tmp);
691 g_free(tmp); 754 g_free(tmp);
755
692 /* subscribe to buddy presence 756 /* subscribe to buddy presence
693 * we dont need to know the status so we do not need a callback */ 757 * we dont need to know the status so we do not need a callback */
694 758
695 send_sip_request(sip->gc, "SUBSCRIBE",to, to, contact, "", NULL, process_subscribe_response); 759 send_sip_request(sip->gc, "SUBSCRIBE", to, to, contact, "", NULL,
760 process_subscribe_response);
696 761
697 g_free(to); 762 g_free(to);
698 g_free(contact); 763 g_free(contact);
699 764
700 /* resubscribe before subscription expires */ 765 /* resubscribe before subscription expires */
702 buddy->resubscribe = time(NULL)+250+(rand()%50); 767 buddy->resubscribe = time(NULL)+250+(rand()%50);
703 } 768 }
704 769
705 static void simple_buddy_resub(char *name, struct simple_buddy *buddy, struct simple_account_data *sip) { 770 static void simple_buddy_resub(char *name, struct simple_buddy *buddy, struct simple_account_data *sip) {
706 time_t curtime = time(NULL); 771 time_t curtime = time(NULL);
707 gaim_debug_info("simple","buddy resub\n"); 772 gaim_debug_info("simple", "buddy resub\n");
708 if(buddy->resubscribe < curtime) { 773 if(buddy->resubscribe < curtime) {
709 gaim_debug(GAIM_DEBUG_MISC, "simple", "simple_buddy_resub %s\n",name); 774 gaim_debug(GAIM_DEBUG_MISC, "simple", "simple_buddy_resub %s\n", name);
710 simple_subscribe(sip, buddy); 775 simple_subscribe(sip, buddy);
711 } 776 }
712 } 777 }
713 778
714 static gboolean resend_timeout(struct simple_account_data *sip) { 779 static gboolean resend_timeout(struct simple_account_data *sip) {
753 } 818 }
754 819
755 return TRUE; 820 return TRUE;
756 } 821 }
757 822
758 static void simple_send_message(struct simple_account_data *sip, char *to, char *msg, char *type) { 823 static void simple_send_message(struct simple_account_data *sip, const char *to, const char *msg, const char *type) {
759 gchar *hdr; 824 gchar *hdr;
760 gchar *fullto; 825 gchar *fullto;
761 if(strncmp("sip:",to,4)) { 826 if(strncmp("sip:", to, 4)) {
762 fullto = g_strdup_printf("sip:%s",to); 827 fullto = g_strdup_printf("sip:%s", to);
763 } else { 828 } else {
764 fullto = g_strdup(to); 829 fullto = g_strdup(to);
765 } 830 }
766 if(type) { 831 if(type) {
767 hdr = g_strdup_printf("Content-Type: %s\r\n",type); 832 hdr = g_strdup_printf("Content-Type: %s\r\n", type);
768 } else { 833 } else {
769 hdr = g_strdup("Content-Type: text/plain\r\n"); 834 hdr = g_strdup("Content-Type: text/plain\r\n");
770 } 835 }
771 send_sip_request(sip->gc, "MESSAGE", fullto, fullto, hdr, msg, NULL, NULL); 836 send_sip_request(sip->gc, "MESSAGE", fullto, fullto, hdr, msg, NULL, NULL);
772 g_free(hdr); 837 g_free(hdr);
798 if(!contenttype || !strncmp(contenttype, "text/plain", 10) || !strncmp(contenttype, "text/html", 9)) { 863 if(!contenttype || !strncmp(contenttype, "text/plain", 10) || !strncmp(contenttype, "text/html", 9)) {
799 serv_got_im(sip->gc, from, msg->body, 0, time(NULL)); 864 serv_got_im(sip->gc, from, msg->body, 0, time(NULL));
800 send_sip_response(sip->gc, msg, 200, "OK", NULL); 865 send_sip_response(sip->gc, msg, 200, "OK", NULL);
801 found = TRUE; 866 found = TRUE;
802 } 867 }
803 if(!strncmp(contenttype, "application/im-iscomposing+xml",30)) { 868 if(!strncmp(contenttype, "application/im-iscomposing+xml", 30)) {
804 xmlnode *isc = xmlnode_from_str(msg->body, msg->bodylen); 869 xmlnode *isc = xmlnode_from_str(msg->body, msg->bodylen);
805 xmlnode *state; 870 xmlnode *state;
806 gchar *statedata; 871 gchar *statedata;
807 872
808 if(!isc) { 873 if(!isc) {
809 gaim_debug_info("simple","process_incoming_message: can not parse iscomposing\n"); 874 gaim_debug_info("simple", "process_incoming_message: can not parse iscomposing\n");
810 return; 875 return;
811 } 876 }
812 877
813 state = xmlnode_get_child(isc, "state"); 878 state = xmlnode_get_child(isc, "state");
814 879
815 if(!state) { 880 if(!state) {
816 gaim_debug_info("simple","process_incoming_message: no state found\n"); 881 gaim_debug_info("simple", "process_incoming_message: no state found\n");
817 return; 882 return;
818 } 883 }
819 884
820 statedata = xmlnode_get_data(state); 885 statedata = xmlnode_get_data(state);
821 if(statedata) { 886 if(statedata) {
822 if(strstr(statedata,"active")) serv_got_typing(sip->gc, from, 0, GAIM_TYPING); 887 if(strstr(statedata, "active")) serv_got_typing(sip->gc, from, 0, GAIM_TYPING);
823 else serv_got_typing_stopped(sip->gc, from); 888 else serv_got_typing_stopped(sip->gc, from);
824 } 889 }
825 xmlnode_free(isc); 890 xmlnode_free(isc);
826 send_sip_response(sip->gc, msg, 200, "OK", NULL); 891 send_sip_response(sip->gc, msg, 200, "OK", NULL);
827 found = TRUE; 892 found = TRUE;
837 gboolean process_register_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { 902 gboolean process_register_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) {
838 gchar *tmp; 903 gchar *tmp;
839 gaim_debug(GAIM_DEBUG_MISC, "simple", "in process register response response: %d\n", msg->response); 904 gaim_debug(GAIM_DEBUG_MISC, "simple", "in process register response response: %d\n", msg->response);
840 switch (msg->response) { 905 switch (msg->response) {
841 case 200: 906 case 200:
842 if(sip->registerstatus<3) { /* registered */ 907 if(sip->registerstatus < 3) { /* registered */
843 if(gaim_account_get_bool(sip->account, "dopublish", TRUE)) { 908 if(gaim_account_get_bool(sip->account, "dopublish", TRUE)) {
844 send_publish(sip); 909 send_publish(sip);
845 } 910 }
846 } 911 }
847 sip->registerstatus=3; 912 sip->registerstatus = 3;
848 gaim_connection_set_state(sip->gc, GAIM_CONNECTED); 913 gaim_connection_set_state(sip->gc, GAIM_CONNECTED);
849 914
850 /* get buddies from blist */ 915 /* get buddies from blist */
851 simple_get_buddies(sip->gc); 916 simple_get_buddies(sip->gc);
852 917
853 subscribe_timeout(sip); 918 subscribe_timeout(sip);
854 break; 919 break;
855 case 401: 920 case 401:
856 if(sip->registerstatus!=2) { 921 if(sip->registerstatus != 2) {
857 gaim_debug_info("simple","REGISTER retries %d\n",sip->registrar.retries); 922 gaim_debug_info("simple", "REGISTER retries %d\n", sip->registrar.retries);
858 if(sip->registrar.retries>3) { 923 if(sip->registrar.retries > 3) {
859 gaim_connection_error(sip->gc,"Wrong Password"); 924 gaim_connection_error(sip->gc, _("Wrong Password"));
860 return TRUE; 925 return TRUE;
861 } 926 }
862 tmp = sipmsg_find_header(msg, "WWW-Authenticate"); 927 tmp = sipmsg_find_header(msg, "WWW-Authenticate");
863 fill_auth(sip, tmp, &sip->registrar); 928 fill_auth(sip, tmp, &sip->registrar);
864 sip->registerstatus=2; 929 sip->registerstatus = 2;
865 do_register(sip); 930 do_register(sip);
866 } 931 }
867 break; 932 break;
868 } 933 }
869 return TRUE; 934 return TRUE;
875 gchar *tmp2; 940 gchar *tmp2;
876 xmlnode *pidf; 941 xmlnode *pidf;
877 xmlnode *basicstatus; 942 xmlnode *basicstatus;
878 gboolean isonline = FALSE; 943 gboolean isonline = FALSE;
879 944
880 fromhdr = sipmsg_find_header(msg,"From"); 945 fromhdr = sipmsg_find_header(msg, "From");
881 from = parse_from(fromhdr); 946 from = parse_from(fromhdr);
882 if(!from) return; 947 if(!from) return;
883 948
884 pidf = xmlnode_from_str(msg->body, msg->bodylen); 949 pidf = xmlnode_from_str(msg->body, msg->bodylen);
885 950
886 if(!pidf) { 951 if(!pidf) {
887 gaim_debug_info("simple","process_incoming_notify: no parseable pidf\n"); 952 gaim_debug_info("simple", "process_incoming_notify: no parseable pidf\n");
888 return; 953 return;
889 } 954 }
890 955
891 basicstatus = xmlnode_get_child(xmlnode_get_child(xmlnode_get_child(pidf,"tuple"),"status"), "basic"); 956 basicstatus = xmlnode_get_child(xmlnode_get_child(xmlnode_get_child(pidf, "tuple"), "status"), "basic");
892 957
893 if(!basicstatus) { 958 if(!basicstatus) {
894 gaim_debug_info("simple","process_incoming_notify: no basic found\n"); 959 gaim_debug_info("simple", "process_incoming_notify: no basic found\n");
895 return; 960 return;
896 } 961 }
897 962
898 tmp2 = xmlnode_get_data(basicstatus); 963 tmp2 = xmlnode_get_data(basicstatus);
899 964
900 if(!tmp2) { 965 if(!tmp2) {
901 gaim_debug_info("simple","process_incoming_notify: no basic data found\n"); 966 gaim_debug_info("simple", "process_incoming_notify: no basic data found\n");
902 return; 967 return;
903 } 968 }
904 969
905 if(strstr(tmp2, "open")) { 970 if(strstr(tmp2, "open")) {
906 isonline = TRUE; 971 isonline = TRUE;
1011 } 1076 }
1012 1077
1013 static void send_publish(struct simple_account_data *sip) { 1078 static void send_publish(struct simple_account_data *sip) {
1014 gchar *uri = g_strdup_printf("sip:%s@%s", sip->username, sip->servername); 1079 gchar *uri = g_strdup_printf("sip:%s@%s", sip->username, sip->servername);
1015 gchar *doc = gen_pidf(sip); 1080 gchar *doc = gen_pidf(sip);
1016 send_sip_request(sip->gc, "PUBLISH", uri, uri, "Expires: 600\r\nEvent: presence\r\nContent-Type: application/pidf+xml\r\n", doc, NULL, process_publish_response); 1081 send_sip_request(sip->gc, "PUBLISH", uri, uri,
1082 "Expires: 600\r\nEvent: presence\r\n"
1083 "Content-Type: application/pidf+xml\r\n",
1084 doc, NULL, process_publish_response);
1017 sip->republish = time(NULL) + 500; 1085 sip->republish = time(NULL) + 500;
1018 g_free(doc); 1086 g_free(doc);
1019 } 1087 }
1020 1088
1021 static void process_incoming_subscribe(struct simple_account_data *sip, struct sipmsg *msg) { 1089 static void process_incoming_subscribe(struct simple_account_data *sip, struct sipmsg *msg) {
1104 struct transaction *trans = transactions_find(sip, msg); 1172 struct transaction *trans = transactions_find(sip, msg);
1105 if(trans) { 1173 if(trans) {
1106 if(msg->response == 407) { 1174 if(msg->response == 407) {
1107 gchar *resend, *auth, *ptmp; 1175 gchar *resend, *auth, *ptmp;
1108 1176
1109 if(sip->proxy.retries>3) return; 1177 if(sip->proxy.retries > 3) return;
1110 sip->proxy.retries++; 1178 sip->proxy.retries++;
1111 /* do proxy authentication */ 1179 /* do proxy authentication */
1112 1180
1113 ptmp = sipmsg_find_header(msg, "Proxy-Authenticate"); 1181 ptmp = sipmsg_find_header(msg, "Proxy-Authenticate");
1114 1182
1122 sendout_pkt(sip->gc, resend); 1190 sendout_pkt(sip->gc, resend);
1123 g_free(resend); 1191 g_free(resend);
1124 } else { 1192 } else {
1125 if(msg->response == 100) { 1193 if(msg->response == 100) {
1126 /* ignore provisional response */ 1194 /* ignore provisional response */
1127 gaim_debug_info("simple","got trying response\n"); 1195 gaim_debug_info("simple", "got trying response\n");
1128 } else { 1196 } else {
1129 sip->proxy.retries = 0; 1197 sip->proxy.retries = 0;
1130 if(msg->response == 401) sip->registrar.retries++; 1198 if(msg->response == 401) sip->registrar.retries++;
1131 else sip->registrar.retries = 0; 1199 else sip->registrar.retries = 0;
1132 if(trans->callback) { 1200 if(trans->callback) {
1140 } else { 1208 } else {
1141 gaim_debug(GAIM_DEBUG_MISC, "simple", "received response to unknown transaction"); 1209 gaim_debug(GAIM_DEBUG_MISC, "simple", "received response to unknown transaction");
1142 } 1210 }
1143 } 1211 }
1144 if(!found) { 1212 if(!found) {
1145 gaim_debug(GAIM_DEBUG_MISC, "simple", "received a unknown sip message with method %s and response %d\n",msg->method, msg->response); 1213 gaim_debug(GAIM_DEBUG_MISC, "simple", "received a unknown sip message with method %s and response %d\n", msg->method, msg->response);
1146 } 1214 }
1147 } 1215 }
1148 1216
1149 static void process_input(struct simple_account_data *sip, struct sip_connection *conn) 1217 static void process_input(struct simple_account_data *sip, struct sip_connection *conn)
1150 { 1218 {
1158 while(*cur == '\r' || *cur == '\n') { 1226 while(*cur == '\r' || *cur == '\n') {
1159 cur++; 1227 cur++;
1160 } 1228 }
1161 if(cur != conn->inbuf) { 1229 if(cur != conn->inbuf) {
1162 memmove(conn->inbuf, cur, conn->inbufused-(cur-conn->inbuf)); 1230 memmove(conn->inbuf, cur, conn->inbufused-(cur-conn->inbuf));
1163 conn->inbufused=strlen(conn->inbuf); 1231 conn->inbufused = strlen(conn->inbuf);
1164 } 1232 }
1165 1233
1166 /* Received a full Header? */ 1234 /* Received a full Header? */
1167 if((cur = strstr(conn->inbuf, "\r\n\r\n"))!=NULL) { 1235 if((cur = strstr(conn->inbuf, "\r\n\r\n")) != NULL) {
1168 time_t currtime = time(NULL); 1236 time_t currtime = time(NULL);
1169 cur += 2; 1237 cur += 2;
1170 cur[0] = '\0'; 1238 cur[0] = '\0';
1171 gaim_debug_info("simple","\n\nreceived - %s\n######\n%s\n#######\n\n",ctime(&currtime), conn->inbuf); 1239 gaim_debug_info("simple", "\n\nreceived - %s\n######\n%s\n#######\n\n", ctime(&currtime), conn->inbuf);
1172 msg = sipmsg_parse_header(conn->inbuf); 1240 msg = sipmsg_parse_header(conn->inbuf);
1173 cur[0] = '\r'; 1241 cur[0] = '\r';
1174 cur += 2; 1242 cur += 2;
1175 restlen = conn->inbufused - (cur-conn->inbuf); 1243 restlen = conn->inbufused - (cur-conn->inbuf);
1176 if(restlen>=msg->bodylen) { 1244 if(restlen >= msg->bodylen) {
1177 dummy = g_malloc(msg->bodylen+1); 1245 dummy = g_malloc(msg->bodylen + 1);
1178 memcpy(dummy, cur, msg->bodylen); 1246 memcpy(dummy, cur, msg->bodylen);
1179 dummy[msg->bodylen]='\0'; 1247 dummy[msg->bodylen] = '\0';
1180 msg->body = dummy; 1248 msg->body = dummy;
1181 cur+=msg->bodylen; 1249 cur += msg->bodylen;
1182 memmove(conn->inbuf, cur, conn->inbuflen-(cur-conn->inbuf)); 1250 memmove(conn->inbuf, cur, conn->inbuflen - (cur - conn->inbuf));
1183 conn->inbufused=strlen(conn->inbuf); 1251 conn->inbufused = strlen(conn->inbuf);
1184 } else { 1252 } else {
1185 sipmsg_free(msg); 1253 sipmsg_free(msg);
1186 return; 1254 return;
1187 } 1255 }
1188 gaim_debug(GAIM_DEBUG_MISC, "simple", "in process response response: %d\n", msg->response); 1256 gaim_debug(GAIM_DEBUG_MISC, "simple", "in process response response: %d\n", msg->response);
1189 process_input_message(sip,msg); 1257 process_input_message(sip, msg);
1190 } else { 1258 } else {
1191 gaim_debug(GAIM_DEBUG_MISC, "simple", "received a incomplete sip msg: %s\n", conn->inbuf); 1259 gaim_debug(GAIM_DEBUG_MISC, "simple", "received a incomplete sip msg: %s\n", conn->inbuf);
1192 } 1260 }
1193 } 1261 }
1194 1262
1200 time_t currtime; 1268 time_t currtime;
1201 1269
1202 static char buffer[65536]; 1270 static char buffer[65536];
1203 if((len = recv(source, buffer, sizeof(buffer) - 1, 0)) > 0) { 1271 if((len = recv(source, buffer, sizeof(buffer) - 1, 0)) > 0) {
1204 buffer[len] = '\0'; 1272 buffer[len] = '\0';
1205 gaim_debug_info("simple","\n\nreceived - %s\n######\n%s\n#######\n\n",ctime(&currtime), buffer); 1273 gaim_debug_info("simple", "\n\nreceived - %s\n######\n%s\n#######\n\n", ctime(&currtime), buffer);
1206 msg = sipmsg_parse_msg(buffer); 1274 msg = sipmsg_parse_msg(buffer);
1207 if(msg) process_input_message(sip, msg); 1275 if(msg) process_input_message(sip, msg);
1208 } 1276 }
1209 } 1277 }
1210 1278
1217 if(!conn) { 1285 if(!conn) {
1218 gaim_debug_error("simple", "Connection not found!\n"); 1286 gaim_debug_error("simple", "Connection not found!\n");
1219 return; 1287 return;
1220 } 1288 }
1221 1289
1222 if (conn->inbuflen < conn->inbufused + SIMPLE_BUF_INC) { 1290 if(conn->inbuflen < conn->inbufused + SIMPLE_BUF_INC) {
1223 conn->inbuflen += SIMPLE_BUF_INC; 1291 conn->inbuflen += SIMPLE_BUF_INC;
1224 conn->inbuf = g_realloc(conn->inbuf, conn->inbuflen); 1292 conn->inbuf = g_realloc(conn->inbuf, conn->inbuflen);
1225 } 1293 }
1226 1294
1227 if ((len = read(source, conn->inbuf + conn->inbufused, SIMPLE_BUF_INC - 1)) <= 0) { 1295 len = read(source, conn->inbuf + conn->inbufused, SIMPLE_BUF_INC - 1);
1228 gaim_debug_info("simple","simple_input_cb: read error\n"); 1296
1297 if(len < 0 && errno == EAGAIN)
1298 return;
1299 else if(len <= 0) {
1300 gaim_debug_info("simple", "simple_input_cb: read error\n");
1229 connection_remove(sip, source); 1301 connection_remove(sip, source);
1230 if(sip->fd == source) sip->fd = -1; 1302 if(sip->fd == source) sip->fd = -1;
1231 return; 1303 return;
1232 } 1304 }
1233 if(len == 0) {
1234 /* connection was closed */
1235 connection_remove(sip, source);
1236 if(sip->fd == source) sip->fd = -1;
1237 }
1238 1305
1239 conn->inbufused += len; 1306 conn->inbufused += len;
1240 conn->inbuf[conn->inbufused]='\0'; 1307 conn->inbuf[conn->inbufused] = '\0';
1241 1308
1242 process_input(sip, conn); 1309 process_input(sip, conn);
1243 } 1310 }
1244 1311
1245 /* Callback for new connections on incoming TCP port */ 1312 /* Callback for new connections on incoming TCP port */
1258 static void login_cb(gpointer data, gint source, GaimInputCondition cond) { 1325 static void login_cb(gpointer data, gint source, GaimInputCondition cond) {
1259 GaimConnection *gc = data; 1326 GaimConnection *gc = data;
1260 struct simple_account_data *sip = gc->proto_data; 1327 struct simple_account_data *sip = gc->proto_data;
1261 struct sip_connection *conn; 1328 struct sip_connection *conn;
1262 1329
1263 if( source < 0 ) { 1330 if(source < 0) {
1264 gaim_connection_error(gc,"Could not connect"); 1331 gaim_connection_error(gc, _("Could not connect"));
1265 return; 1332 return;
1266 } 1333 }
1267 1334
1268 sip->fd = source; 1335 sip->fd = source;
1269 1336
1349 1416
1350 gaim_debug_info("simple", "listenfd: %d\n", sip->listenfd); 1417 gaim_debug_info("simple", "listenfd: %d\n", sip->listenfd);
1351 sip->listenport = gaim_network_get_port_from_fd(sip->listenfd); 1418 sip->listenport = gaim_network_get_port_from_fd(sip->listenfd);
1352 sip->listenpa = gaim_input_add(sip->listenfd, GAIM_INPUT_READ, 1419 sip->listenpa = gaim_input_add(sip->listenfd, GAIM_INPUT_READ,
1353 simple_newconn_cb, sip->gc); 1420 simple_newconn_cb, sip->gc);
1354 gaim_debug_info("simple","connecting to %s port %d\n", 1421 gaim_debug_info("simple", "connecting to %s port %d\n",
1355 sip->realhostname, sip->realport); 1422 sip->realhostname, sip->realport);
1356 /* open tcp connection to the server */ 1423 /* open tcp connection to the server */
1357 error = gaim_proxy_connect(sip->account, sip->realhostname, 1424 error = gaim_proxy_connect(sip->account, sip->realhostname,
1358 sip->realport, login_cb, sip->gc); 1425 sip->realport, login_cb, sip->gc);
1359 if(error) { 1426 if(error) {
1364 static void srvresolved(GaimSrvResponse *resp, int results, gpointer data) { 1431 static void srvresolved(GaimSrvResponse *resp, int results, gpointer data) {
1365 struct simple_account_data *sip = (struct simple_account_data*) data; 1432 struct simple_account_data *sip = (struct simple_account_data*) data;
1366 1433
1367 gchar *hostname; 1434 gchar *hostname;
1368 int port = gaim_account_get_int(sip->account, "port", 0); 1435 int port = gaim_account_get_int(sip->account, "port", 0);
1369
1370 1436
1371 /* find the host to connect to */ 1437 /* find the host to connect to */
1372 if(results) { 1438 if(results) {
1373 hostname = g_strdup(resp->hostname); 1439 hostname = g_strdup(resp->hostname);
1374 if(!port) 1440 if(!port)
1383 } 1449 }
1384 1450
1385 sip->realhostname = hostname; 1451 sip->realhostname = hostname;
1386 sip->realport = port; 1452 sip->realport = port;
1387 if(!sip->realport) sip->realport = 5060; 1453 if(!sip->realport) sip->realport = 5060;
1454
1388 /* TCP case */ 1455 /* TCP case */
1389 if(! sip->udp) { 1456 if(!sip->udp) {
1390 /* create socket for incoming connections */ 1457 /* create socket for incoming connections */
1391 if(!gaim_network_listen_range(5060, 5160, SOCK_STREAM, 1458 if(!gaim_network_listen_range(5060, 5160, SOCK_STREAM,
1392 simple_tcp_connect_listen_cb, sip)) { 1459 simple_tcp_connect_listen_cb, sip)) {
1393 gaim_connection_error(sip->gc, _("Could not create listen socket")); 1460 gaim_connection_error(sip->gc, _("Could not create listen socket"));
1394 return; 1461 return;
1406 struct simple_account_data *sip; 1473 struct simple_account_data *sip;
1407 gchar **userserver; 1474 gchar **userserver;
1408 gchar *hosttoconnect; 1475 gchar *hosttoconnect;
1409 1476
1410 const char *username = gaim_account_get_username(account); 1477 const char *username = gaim_account_get_username(account);
1411
1412 gc = gaim_account_get_connection(account); 1478 gc = gaim_account_get_connection(account);
1413 gc->proto_data = sip = g_new0(struct simple_account_data,1); 1479
1414 sip->gc=gc; 1480 if (strpbrk(username, " \t\v\r\n") != NULL) {
1481 gaim_connection_error(gc, _("SIP usernames may not contain whitespaces or @ symbols"));
1482 return;
1483 }
1484
1485 gc->proto_data = sip = g_new0(struct simple_account_data, 1);
1486 sip->gc = gc;
1415 sip->account = account; 1487 sip->account = account;
1416 sip->registerexpire = 900; 1488 sip->registerexpire = 900;
1417 sip->udp = gaim_account_get_bool(account, "udp", FALSE); 1489 sip->udp = gaim_account_get_bool(account, "udp", FALSE);
1418 if (strpbrk(username, " \t\v\r\n") != NULL) { 1490 /* TODO: is there a good default grow size? */
1419 gaim_connection_error(gc, _("SIP usernames may not contain whitespaces or @ symbols")); 1491 if(!sip->udp)
1420 return; 1492 sip->txbuf = gaim_circ_buffer_new(0);
1421 }
1422 1493
1423 userserver = g_strsplit(username, "@", 2); 1494 userserver = g_strsplit(username, "@", 2);
1424 gaim_connection_set_display_name(gc,userserver[0]); 1495 gaim_connection_set_display_name(gc, userserver[0]);
1425 sip->username = g_strdup(userserver[0]); 1496 sip->username = g_strdup(userserver[0]);
1426 sip->servername = g_strdup(userserver[1]); 1497 sip->servername = g_strdup(userserver[1]);
1427 sip->password = g_strdup(gaim_connection_get_password(gc)); 1498 sip->password = g_strdup(gaim_connection_get_password(gc));
1428 g_strfreev(userserver); 1499 g_strfreev(userserver);
1429 1500
1439 } else { 1510 } else {
1440 hosttoconnect = g_strdup(gaim_account_get_string(account, "proxy", sip->servername)); 1511 hosttoconnect = g_strdup(gaim_account_get_string(account, "proxy", sip->servername));
1441 } 1512 }
1442 1513
1443 /* TCP case */ 1514 /* TCP case */
1444 if(! sip->udp) { 1515 if(!sip->udp) {
1445 gaim_srv_resolve("sip","tcp",hosttoconnect,srvresolved, sip); 1516 gaim_srv_resolve("sip", "tcp", hosttoconnect, srvresolved, sip);
1446 } else { /* UDP */ 1517 } else { /* UDP */
1447 gaim_srv_resolve("sip","udp",hosttoconnect,srvresolved, sip); 1518 gaim_srv_resolve("sip", "udp", hosttoconnect, srvresolved, sip);
1448 } 1519 }
1449 g_free(hosttoconnect); 1520 g_free(hosttoconnect);
1450 } 1521 }
1451 1522
1452 static void simple_close(GaimConnection *gc) 1523 static void simple_close(GaimConnection *gc)
1468 g_free(sip->proxy.nonce); 1539 g_free(sip->proxy.nonce);
1469 g_free(sip->proxy.opaque); 1540 g_free(sip->proxy.opaque);
1470 g_free(sip->proxy.target); 1541 g_free(sip->proxy.target);
1471 g_free(sip->proxy.realm); 1542 g_free(sip->proxy.realm);
1472 g_free(sip->proxy.digest_session_key); 1543 g_free(sip->proxy.digest_session_key);
1473 g_free(sip->sendlater); 1544 if(sip->txbuf)
1545 gaim_circ_buffer_destroy(sip->txbuf);
1474 g_free(sip->realhostname); 1546 g_free(sip->realhostname);
1475 if(sip->listenpa) gaim_input_remove(sip->listenpa); 1547 if(sip->listenpa) gaim_input_remove(sip->listenpa);
1548 if(sip->tx_handler) gaim_input_remove(sip->tx_handler);
1476 if(sip->resendtimeout) gaim_timeout_remove(sip->resendtimeout); 1549 if(sip->resendtimeout) gaim_timeout_remove(sip->resendtimeout);
1477 if(sip->registertimeout) gaim_timeout_remove(sip->registertimeout); 1550 if(sip->registertimeout) gaim_timeout_remove(sip->registertimeout);
1478 sip->servername = sip->username = sip->password = sip->registrar.nonce = sip->registrar.realm = sip->proxy.nonce = sip->proxy.realm = sip->sendlater = sip->realhostname = NULL;
1479 } 1551 }
1480 g_free(gc->proto_data); 1552 g_free(gc->proto_data);
1481 gc->proto_data = NULL; 1553 gc->proto_data = NULL;
1482 } 1554 }
1483 1555
1595 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 1667 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1596 1668
1597 option = gaim_account_option_int_new(_("Connect port"), "port", 0); 1669 option = gaim_account_option_int_new(_("Connect port"), "port", 0);
1598 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 1670 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1599 1671
1600
1601 option = gaim_account_option_bool_new(_("Use UDP"), "udp", FALSE); 1672 option = gaim_account_option_bool_new(_("Use UDP"), "udp", FALSE);
1602 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 1673 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1603 option = gaim_account_option_bool_new(_("Use proxy"), "useproxy", FALSE); 1674 option = gaim_account_option_bool_new(_("Use proxy"), "useproxy", FALSE);
1604 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 1675 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1605 option = gaim_account_option_string_new(_("Proxy"), "proxy", ""); 1676 option = gaim_account_option_string_new(_("Proxy"), "proxy", "");