| 257 static void sendlater(GaimConnection *gc, const char *buf) { |
258 static void sendlater(GaimConnection *gc, const char *buf) { |
| 258 struct getserver_return *serveradr; |
259 struct getserver_return *serveradr; |
| 259 struct simple_account_data *sip = gc->proto_data; |
260 struct simple_account_data *sip = gc->proto_data; |
| 260 int error = 0; |
261 int error = 0; |
| 261 if(!sip->connecting) { |
262 if(!sip->connecting) { |
| 262 serveradr = getserver(sip->servername); |
263 serveradr = getserver(sip->servername, "_sip._tcp"); |
| 263 gaim_debug_info("simple","connecting to %s port %d", serveradr->name, serveradr->port); |
264 gaim_debug_info("simple","connecting to %s port %d", serveradr->name, serveradr->port); |
| 264 error = gaim_proxy_connect(sip->account, serveradr->name, serveradr->port, send_later_cb, gc); |
265 error = gaim_proxy_connect(sip->account, serveradr->name, serveradr->port, send_later_cb, gc); |
| 265 if(error) { |
266 if(error) { |
| 266 gaim_connection_error(gc, _("Couldn't create socket")); |
267 gaim_connection_error(gc, _("Couldn't create socket")); |
| 267 } |
268 } |
| 276 } |
277 } |
| 277 |
278 |
| 278 static int sendout_pkt(GaimConnection *gc, const char *buf) { |
279 static int sendout_pkt(GaimConnection *gc, const char *buf) { |
| 279 struct simple_account_data *sip = gc->proto_data; |
280 struct simple_account_data *sip = gc->proto_data; |
| 280 time_t currtime = time(NULL); |
281 time_t currtime = time(NULL); |
| 281 int ret; |
282 int ret = 0; |
| 282 |
283 |
| 283 gaim_debug(GAIM_DEBUG_MISC, "simple", "\n\nsending - %s\n######\n%s\n######\n\n", ctime(&currtime), buf); |
284 gaim_debug(GAIM_DEBUG_MISC, "simple", "\n\nsending - %s\n######\n%s\n######\n\n", ctime(&currtime), buf); |
| 284 if(sip->fd <0 ) { |
285 if(sip->udp) { |
| 285 sendlater(gc, buf); |
286 if(sendto(sip->fd, buf, strlen(buf), 0, (struct sockaddr*)&sip->serveraddr, sizeof(struct sockaddr_in)) < strlen(buf)) { |
| 286 return 0; |
287 gaim_debug_info("simple", "could not send packet\n"); |
| 287 } |
288 } |
| 288 ret = write(sip->fd, buf, strlen(buf)); |
289 } else { |
| 289 if(ret < 0) { |
290 if(sip->fd <0 ) { |
| 290 sendlater(gc,buf); |
291 sendlater(gc, buf); |
| 291 return 0; |
292 return 0; |
| |
293 } |
| |
294 ret = write(sip->fd, buf, strlen(buf)); |
| |
295 if(ret < 0) { |
| |
296 sendlater(gc,buf); |
| |
297 return 0; |
| |
298 } |
| 292 } |
299 } |
| 293 return ret; |
300 return ret; |
| 294 } |
301 } |
| 295 |
302 |
| 296 static void send_sip_response(GaimConnection *gc, struct sipmsg *msg, int code, char *text, char *body) { |
303 static void send_sip_response(GaimConnection *gc, struct sipmsg *msg, int code, char *text, char *body) { |
| 414 struct simple_account_data *sip = gc->proto_data; |
421 struct simple_account_data *sip = gc->proto_data; |
| 415 sip->registerstatus = 1; |
422 sip->registerstatus = 1; |
| 416 |
423 |
| 417 char *uri = g_strdup_printf("sip:%s",sip->servername); |
424 char *uri = g_strdup_printf("sip:%s",sip->servername); |
| 418 char *to = g_strdup_printf("sip:%s@%s",sip->username,sip->servername); |
425 char *to = g_strdup_printf("sip:%s@%s",sip->username,sip->servername); |
| 419 char *contact = g_strdup_printf("Contact: <sip:%s@%s:%d;transport=tcp>;methods=\"MESSAGE, SUBSCRIBE, NOTIFY\"\r\nExpires: 900\r\n", sip->username, sip->ip, sip->listenport); |
426 char *contact = g_strdup_printf("Contact: <sip:%s@%s:%d;transport=%s>;methods=\"MESSAGE, SUBSCRIBE, NOTIFY\"\r\nExpires: 900\r\n", sip->username, sip->ip, sip->listenport, sip->udp ? "udp" : "tcp"); |
| 420 |
427 |
| 421 // allow one auth try per register |
428 // allow one auth try per register |
| 422 sip->proxy.fouroseven = 0; |
429 sip->proxy.fouroseven = 0; |
| 423 sip->registrar.fouroseven = 0; |
430 sip->registrar.fouroseven = 0; |
| 424 |
431 |
| 802 send_sip_response(sip->gc, msg, 200, "Ok", NULL); |
809 send_sip_response(sip->gc, msg, 200, "Ok", NULL); |
| 803 g_free(tmp); |
810 g_free(tmp); |
| 804 send_notify(sip, watcher); |
811 send_notify(sip, watcher); |
| 805 } |
812 } |
| 806 |
813 |
| |
814 static void process_input_message(struct simple_account_data *sip, struct sipmsg *msg) { |
| |
815 int found = 0; |
| |
816 if( msg->response == 0 ) { // request |
| |
817 if(!strcmp(msg->method, "MESSAGE")) { |
| |
818 process_incoming_message(sip, msg); |
| |
819 found = 1; |
| |
820 } |
| |
821 if(!strcmp(msg->method, "NOTIFY")) { |
| |
822 process_incoming_notify(sip, msg); |
| |
823 found = 1; |
| |
824 } |
| |
825 if(!strcmp(msg->method, "SUBSCRIBE")) { |
| |
826 process_incoming_subscribe(sip, msg); |
| |
827 found = 1; |
| |
828 } |
| |
829 } else { // response |
| |
830 struct transaction *trans = transactions_find(sip, msg); |
| |
831 if(trans) { |
| |
832 if(msg->response == 407) { |
| |
833 if(sip->proxy.fouroseven>3) return; |
| |
834 sip->proxy.fouroseven++; |
| |
835 // do proxy authentication |
| |
836 |
| |
837 gchar *ptmp = sipmsg_find_header(msg,"Proxy-Authenticate"); |
| |
838 gchar *resend; |
| |
839 gchar *auth; |
| |
840 |
| |
841 HASHHEX HA2; |
| |
842 HASHHEX response; |
| |
843 gchar noncecount[90]; |
| |
844 fill_auth(sip, ptmp, &sip->proxy); |
| |
845 sprintf(noncecount, "%08d", sip->proxy.nc++); |
| |
846 |
| |
847 DigestCalcResponse(sip->proxy.HA1, sip->proxy.nonce, noncecount, "", "", trans->msg->method, trans->msg->target, HA2, response); |
| |
848 gaim_debug(GAIM_DEBUG_MISC, "simple", "response %s\n", response); |
| |
849 auth = g_strdup_printf("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", nc=\"%s\", response=\"%s\"\r\n",sip->username, sip->proxy.realm, sip->proxy.nonce, trans->msg->target, noncecount, response); |
| |
850 sipmsg_remove_header(msg, "Proxy-Authorization"); |
| |
851 sipmsg_add_header(trans->msg, "Proxy-Authorization", auth); |
| |
852 g_free(auth); |
| |
853 resend = sipmsg_to_string(trans->msg); |
| |
854 // resend request |
| |
855 sendout_pkt(sip->gc, resend); |
| |
856 g_free(resend); |
| |
857 } else { |
| |
858 sip->proxy.fouroseven = 0; |
| |
859 if(msg->response == 401) sip->registrar.fouroseven++; |
| |
860 else sip->registrar.fouroseven = 0; |
| |
861 if(trans->callback) { |
| |
862 // call the callback to process response |
| |
863 (trans->callback)(sip, msg, trans); |
| |
864 sip->transactions = g_slist_remove(sip->transactions, trans); |
| |
865 } else { |
| |
866 // transaction has no callback - just remove it |
| |
867 sip->transactions = g_slist_remove(sip->transactions, trans); |
| |
868 } |
| |
869 } |
| |
870 found = 1; |
| |
871 } else { |
| |
872 gaim_debug(GAIM_DEBUG_MISC, "simple", "received response to unknown transaction"); |
| |
873 } |
| |
874 } |
| |
875 if(!found) { |
| |
876 gaim_debug(GAIM_DEBUG_MISC, "simple", "received a unknown sip message with method %sand response %d\n",msg->method, msg->response); |
| |
877 } |
| |
878 } |
| |
879 |
| 807 static void process_input(struct simple_account_data *sip, struct sip_connection *conn) |
880 static void process_input(struct simple_account_data *sip, struct sip_connection *conn) |
| 808 { |
881 { |
| 809 char *cur; |
882 char *cur; |
| 810 char *dummy; |
883 char *dummy; |
| 811 struct sipmsg *msg; |
884 struct sipmsg *msg; |
| 812 int restlen; |
885 int restlen; |
| 813 int found=0; |
|
| 814 |
886 |
| 815 cur = conn->inbuf; |
887 cur = conn->inbuf; |
| 816 |
888 |
| 817 // according to the RFC remove CRLF at the beginning |
889 // according to the RFC remove CRLF at the beginning |
| 818 while(*cur == '\r' || *cur == '\n') { |
890 while(*cur == '\r' || *cur == '\n') { |
| 844 } else { |
916 } else { |
| 845 sipmsg_free(msg); |
917 sipmsg_free(msg); |
| 846 return; |
918 return; |
| 847 } |
919 } |
| 848 // sipmsg_print(msg); |
920 // sipmsg_print(msg); |
| 849 gaim_debug(GAIM_DEBUG_MISC, "simple", "in process response response: %d\n", msg->response); |
921 gaim_debug(GAIM_DEBUG_MISC, "simple", "in process response response: %d\n", msg->response); |
| 850 if( msg->response == 0 ) { // request |
922 process_input_message(sip,msg); |
| 851 if(!strcmp(msg->method, "MESSAGE")) { |
|
| 852 process_incoming_message(sip, msg); |
|
| 853 found = 1; |
|
| 854 } |
|
| 855 if(!strcmp(msg->method, "NOTIFY")) { |
|
| 856 process_incoming_notify(sip, msg); |
|
| 857 found = 1; |
|
| 858 } |
|
| 859 if(!strcmp(msg->method, "SUBSCRIBE")) { |
|
| 860 process_incoming_subscribe(sip, msg); |
|
| 861 found = 1; |
|
| 862 } |
|
| 863 } else { // response |
|
| 864 struct transaction *trans = transactions_find(sip, msg); |
|
| 865 if(trans) { |
|
| 866 if(msg->response == 407) { |
|
| 867 if(sip->proxy.fouroseven>3) return; |
|
| 868 sip->proxy.fouroseven++; |
|
| 869 // do proxy authentication |
|
| 870 |
|
| 871 gchar *ptmp = sipmsg_find_header(msg,"Proxy-Authenticate"); |
|
| 872 gchar *resend; |
|
| 873 gchar *auth; |
|
| 874 |
|
| 875 HASHHEX HA2; |
|
| 876 HASHHEX response; |
|
| 877 gchar noncecount[90]; |
|
| 878 fill_auth(sip, ptmp, &sip->proxy); |
|
| 879 sprintf(noncecount, "%08d", sip->proxy.nc++); |
|
| 880 |
|
| 881 DigestCalcResponse(sip->proxy.HA1, sip->proxy.nonce, noncecount, "", "", trans->msg->method, trans->msg->target, HA2, response); |
|
| 882 gaim_debug(GAIM_DEBUG_MISC, "simple", "response %s\n", response); |
|
| 883 auth = g_strdup_printf("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", nc=\"%s\", response=\"%s\"\r\n",sip->username, sip->proxy.realm, sip->proxy.nonce, trans->msg->target, noncecount, response); |
|
| 884 sipmsg_remove_header(msg, "Proxy-Authorization"); |
|
| 885 sipmsg_add_header(trans->msg, "Proxy-Authorization", auth); |
|
| 886 g_free(auth); |
|
| 887 resend = sipmsg_to_string(trans->msg); |
|
| 888 // resend request |
|
| 889 sendout_pkt(sip->gc, resend); |
|
| 890 g_free(resend); |
|
| 891 } else { |
|
| 892 sip->proxy.fouroseven = 0; |
|
| 893 if(msg->response == 401) sip->registrar.fouroseven++; |
|
| 894 else sip->registrar.fouroseven = 0; |
|
| 895 if(trans->callback) { |
|
| 896 // call the callback to process response |
|
| 897 (trans->callback)(sip, msg, trans); |
|
| 898 |
|
| 899 sip->transactions = g_slist_remove(sip->transactions, trans); |
|
| 900 } else { |
|
| 901 // transaction has no callback - just remove it |
|
| 902 sip->transactions = g_slist_remove(sip->transactions, trans); |
|
| 903 } |
|
| 904 } |
|
| 905 found = 1; |
|
| 906 } else { |
|
| 907 gaim_debug(GAIM_DEBUG_MISC, "simple", "received response to unknown transaction"); |
|
| 908 } |
|
| 909 } |
|
| 910 if(!found) { |
|
| 911 gaim_debug(GAIM_DEBUG_MISC, "simple", "received a unknown sip message with method %sand response %d\n",msg->method, msg->response); |
|
| 912 } |
|
| 913 } else { |
923 } else { |
| 914 gaim_debug(GAIM_DEBUG_MISC, "simple", "received a incomplete sip msg: %s\n", conn->inbuf); |
924 gaim_debug(GAIM_DEBUG_MISC, "simple", "received a incomplete sip msg: %s\n", conn->inbuf); |
| 915 } |
925 } |
| |
926 } |
| |
927 |
| |
928 static void simple_udp_process(gpointer data, gint source, GaimInputCondition con) { |
| |
929 GaimConnection *gc = data; |
| |
930 struct simple_account_data *sip = gc->proto_data; |
| |
931 struct sipmsg *msg; |
| |
932 int len; |
| |
933 time_t currtime; |
| |
934 |
| |
935 static char buffer[65536]; |
| |
936 len = recv(source, buffer, 65536, 0); |
| |
937 buffer[len] = 0; |
| |
938 gaim_debug_info("simple","\n\nreceived - %s\n######\n%s\n#######\n\n",ctime(&currtime), buffer); |
| |
939 msg = sipmsg_parse_msg(buffer); |
| |
940 if(msg) process_input_message(sip, msg); |
| 916 } |
941 } |
| 917 |
942 |
| 918 static void simple_input_cb(gpointer data, gint source, GaimInputCondition cond) |
943 static void simple_input_cb(gpointer data, gint source, GaimInputCondition cond) |
| 919 { |
944 { |
| 920 GaimConnection *gc = data; |
945 GaimConnection *gc = data; |
| 1032 sip->buddies = g_hash_table_new((GHashFunc)simple_ht_hash_nick, (GEqualFunc)simple_ht_equals_nick); |
1059 sip->buddies = g_hash_table_new((GHashFunc)simple_ht_hash_nick, (GEqualFunc)simple_ht_equals_nick); |
| 1033 |
1060 |
| 1034 gaim_connection_update_progress(gc, _("Connecting"), 1, 2); |
1061 gaim_connection_update_progress(gc, _("Connecting"), 1, 2); |
| 1035 |
1062 |
| 1036 sip->status = g_strdup("available"); |
1063 sip->status = g_strdup("available"); |
| 1037 |
1064 |
| 1038 // search for SRV record |
1065 // TCP case |
| 1039 serveradr = getserver(sip->servername); |
1066 if(! sip->udp) { |
| 1040 gaim_debug_info("simple","connecting to %s port %d", serveradr->name, serveradr->port); |
1067 // search for SRV record |
| 1041 |
1068 serveradr = getserver(sip->servername, "_sip._tcp"); |
| 1042 // open tcp connection to the server |
1069 gaim_debug_info("simple","connecting to %s port %d", serveradr->name, serveradr->port); |
| 1043 error = gaim_proxy_connect(account, serveradr->name, serveradr->port, login_cb, gc); |
1070 |
| 1044 if(error) { |
1071 // open tcp connection to the server |
| 1045 gaim_connection_error(gc, _("Couldn't create socket")); |
1072 error = gaim_proxy_connect(account, serveradr->name, serveradr->port, login_cb, gc); |
| 1046 } |
1073 if(error) { |
| 1047 |
1074 gaim_connection_error(gc, _("Couldn't create socket")); |
| 1048 // create socket for incoming connections |
1075 } |
| 1049 sip->listenfd = gaim_network_listen_range(5060, 5080); |
1076 |
| 1050 if(sip->listenfd == -1) { |
1077 // create socket for incoming connections |
| 1051 gaim_connection_error(gc, _("Could not create listen socket")); |
1078 sip->listenfd = gaim_network_listen_range(5060, 5080); |
| 1052 return; |
1079 if(sip->listenfd == -1) { |
| 1053 } |
1080 gaim_connection_error(gc, _("Could not create listen socket")); |
| 1054 sip->listenport = gaim_network_get_port_from_fd(sip->listenfd); |
1081 return; |
| 1055 gaim_input_add(sip->listenfd, GAIM_INPUT_READ, simple_newconn_cb, gc); |
1082 } |
| 1056 |
1083 sip->listenport = gaim_network_get_port_from_fd(sip->listenfd); |
| |
1084 gaim_input_add(sip->listenfd, GAIM_INPUT_READ, simple_newconn_cb, gc); |
| |
1085 } else { // UDP |
| |
1086 // search for SRV record |
| |
1087 struct sockaddr_in addr; |
| |
1088 struct hostent *h; |
| |
1089 |
| |
1090 serveradr = getserver(sip->servername, "_sip._udp"); |
| |
1091 gaim_debug_info("simple", "using udp with server %s and port %d", serveradr->name, serveradr->port); |
| |
1092 sip->fd = socket(AF_INET, SOCK_DGRAM, 0); |
| |
1093 |
| |
1094 addr.sin_family = AF_INET; |
| |
1095 addr.sin_port = htons(5060); |
| |
1096 addr.sin_addr.s_addr = INADDR_ANY; |
| |
1097 while((bind(sip->fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) <0) && ntohs(addr.sin_port)<5160) { |
| |
1098 addr.sin_port = htons(ntohs(addr.sin_port)+1); |
| |
1099 } |
| |
1100 sip->listenport = ntohs(addr.sin_port); |
| |
1101 sip->listenfd = sip->fd; |
| |
1102 |
| |
1103 gaim_input_add(sip->fd, GAIM_INPUT_READ, simple_udp_process, gc); |
| |
1104 // TODO - change to new SRV impl. |
| |
1105 sip->serveraddr.sin_family = AF_INET; |
| |
1106 sip->serveraddr.sin_port = htons(serveradr->port); |
| |
1107 |
| |
1108 h = gethostbyname(serveradr->name); |
| |
1109 sip->serveraddr.sin_addr.s_addr = ((struct in_addr*)h->h_addr)->s_addr; |
| |
1110 sip->ip = g_strdup(gaim_network_get_my_ip(sip->listenfd)); |
| |
1111 |
| |
1112 do_register(gc); |
| |
1113 |
| |
1114 } |
| |
1115 |
| 1057 // register timeout callback for register / subscribe renewal |
1116 // register timeout callback for register / subscribe renewal |
| 1058 sip->registertimeout = gaim_timeout_add((rand()%10)+10*1000, (GSourceFunc)register_timeout, sip); |
1117 sip->registertimeout = gaim_timeout_add((rand()%10)+10*1000, (GSourceFunc)register_timeout, sip); |
| 1059 } |
1118 } |
| 1060 |
1119 |
| 1061 static void simple_close(GaimConnection *gc) |
1120 static void simple_close(GaimConnection *gc) |
| 1173 }; |
1232 }; |
| 1174 |
1233 |
| 1175 static void _init_plugin(GaimPlugin *plugin) |
1234 static void _init_plugin(GaimPlugin *plugin) |
| 1176 { |
1235 { |
| 1177 GaimAccountUserSplit *split; |
1236 GaimAccountUserSplit *split; |
| |
1237 GaimAccountOption *option; |
| 1178 |
1238 |
| 1179 gaim_debug_register_category("simple"); |
1239 gaim_debug_register_category("simple"); |
| 1180 |
1240 |
| 1181 split = gaim_account_user_split_new(_("Server"), "blubb.com", '@'); |
1241 split = gaim_account_user_split_new(_("Server"), "blubb.com", '@'); |
| 1182 prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); |
1242 prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); |
| 1183 |
1243 |
| |
1244 option = gaim_account_option_bool_new(_("Use UDP"), "udp", FALSE); |
| |
1245 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); |
| 1184 // _simple_plugin = plugin; |
1246 // _simple_plugin = plugin; |
| 1185 } |
1247 } |
| 1186 |
1248 |
| 1187 GAIM_INIT_PLUGIN(simple, _init_plugin, info); |
1249 GAIM_INIT_PLUGIN(simple, _init_plugin, info); |