Mercurial > pidgin
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", ""); |
