Mercurial > pidgin
annotate src/protocols/simple/simple.c @ 11572:7be60d01519f
[gaim-migrate @ 13840]
This should be more robust when dealing with different versions of iconv - we parse out the BOM and explicitly tell iconv what to do. This was lifted from the gtkhtml source. Ethan was concerned that some iconv implementations might be confused with the naming of the explicit charsets (UCS-2LE and UCS-2BE), so we should keep that in mind if people are having problems. This fixes the problem I was having that was caused by the BOM being removed by iconv during the UCS-2 to UTF-8 conversion. There is also some distracting whitespace fixing here to obscure any mistakes that I might have made.
committer: Tailor Script <tailor@pidgin.im>
| author | Daniel Atallah <daniel.atallah@gmail.com> |
|---|---|
| date | Tue, 27 Sep 2005 14:26:11 +0000 |
| parents | a26eb48d1953 |
| children | 1f95b6308195 |
| rev | line source |
|---|---|
| 11181 | 1 /** |
| 2 * @file simple.c | |
| 3 * | |
| 4 * gaim | |
| 5 * | |
| 6 * Copyright (C) 2005 Thomas Butter <butter@uni-mannheim.de> | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
7 * |
| 11345 | 8 * *** |
| 9 * Thanks to Google's Summer of Code Program and the helpful mentors | |
| 10 * *** | |
| 11181 | 11 * |
| 12 * This program is free software; you can redistribute it and/or modify | |
| 13 * it under the terms of the GNU General Public License as published by | |
| 14 * the Free Software Foundation; either version 2 of the License, or | |
| 15 * (at your option) any later version. | |
| 16 * | |
| 17 * This program is distributed in the hope that it will be useful, | |
| 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 20 * GNU General Public License for more details. | |
| 21 * | |
| 22 * You should have received a copy of the GNU General Public License | |
| 23 * along with this program; if not, write to the Free Software | |
| 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 25 */ | |
| 26 | |
| 27 #include "internal.h" | |
| 28 | |
| 29 #include "accountopt.h" | |
| 30 #include "blist.h" | |
| 31 #include "conversation.h" | |
| 32 #include "debug.h" | |
| 33 #include "notify.h" | |
| 11345 | 34 #include "privacy.h" |
| 11181 | 35 #include "prpl.h" |
| 36 #include "plugin.h" | |
| 37 #include "util.h" | |
| 38 #include "version.h" | |
| 39 #include "network.h" | |
| 40 #include "xmlnode.h" | |
| 41 | |
| 42 #include "simple.h" | |
| 43 #include "sipmsg.h" | |
| 11383 | 44 #include "dnssrv.h" |
| 11409 | 45 #include "ntlm.h" |
| 11181 | 46 |
| 47 static char *gentag() { | |
| 48 return g_strdup_printf("%04d%04d", rand() & 0xFFFF, rand() & 0xFFFF); | |
| 49 } | |
| 50 | |
| 51 static char *genbranch() { | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
52 return g_strdup_printf("z9hG4bK%04X%04X%04X%04X%04X", |
| 11181 | 53 rand() & 0xFFFF, |
| 54 rand() & 0xFFFF, | |
| 55 rand() & 0xFFFF, | |
| 56 rand() & 0xFFFF, | |
| 57 rand() & 0xFFFF); | |
| 58 } | |
| 59 | |
| 60 static char *gencallid() { | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
61 return g_strdup_printf("%04Xg%04Xa%04Xi%04Xm%04Xt%04Xb%04Xx%04Xx", |
| 11181 | 62 rand() & 0xFFFF, |
| 63 rand() & 0xFFFF, | |
| 64 rand() & 0xFFFF, | |
| 65 rand() & 0xFFFF, | |
| 66 rand() & 0xFFFF, | |
| 67 rand() & 0xFFFF, | |
| 68 rand() & 0xFFFF, | |
| 69 rand() & 0xFFFF); | |
| 70 } | |
| 71 | |
| 72 static const char *simple_list_icon(GaimAccount *a, GaimBuddy *b) { | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
73 return "simple"; |
| 11181 | 74 } |
| 75 | |
| 76 static void simple_keep_alive(GaimConnection *gc) { | |
| 11194 | 77 struct simple_account_data *sip = gc->proto_data; |
| 11341 | 78 if(sip->udp) { /* in case of UDP send a packet only with a 0 byte to |
| 79 remain in the NAT table */ | |
| 11194 | 80 gchar buf[2]={0,0}; |
| 81 gaim_debug_info("simple", "sending keep alive\n"); | |
| 82 sendto(sip->fd, buf, 1, 0, (struct sockaddr*)&sip->serveraddr, sizeof(struct sockaddr_in)); | |
| 83 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
84 return; |
| 11181 | 85 } |
| 86 | |
| 87 static gboolean process_register_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc); | |
| 88 static void send_notify(struct simple_account_data *sip, struct simple_watcher *); | |
| 89 | |
| 90 static void send_publish(struct simple_account_data *sip); | |
| 91 | |
| 92 static void do_notifies(struct simple_account_data *sip) { | |
| 93 GSList *tmp = sip->watcher; | |
| 94 gaim_debug_info("simple", "do_notifies()\n"); | |
| 11345 | 95 if((sip->republish != -1) || sip->republish < time(NULL)) { |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
96 if(gaim_account_get_bool(sip->account, "dopublish", TRUE)) { |
| 11345 | 97 send_publish(sip); |
| 98 } | |
| 99 } | |
| 11181 | 100 |
| 101 while(tmp) { | |
| 102 gaim_debug_info("simple", "notifying %s\n", ((struct simple_watcher*)tmp->data)->name); | |
| 103 send_notify(sip, tmp->data); | |
| 104 tmp = tmp->next; | |
| 105 } | |
| 106 } | |
| 107 | |
| 108 static void simple_set_status(GaimAccount *account, GaimStatus *status) { | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
109 GaimStatusPrimitive primitive = gaim_status_type_get_primitive(gaim_status_get_type(status)); |
| 11181 | 110 struct simple_account_data *sip = NULL; |
| 111 if (!gaim_status_is_active(status)) | |
| 112 return; | |
| 113 | |
| 114 if(account->gc) sip = account->gc->proto_data; | |
| 115 if(sip) { | |
| 116 if(sip->status) g_free(sip->status); | |
| 117 if(primitive == GAIM_STATUS_AVAILABLE) sip->status = g_strdup("available"); | |
| 118 else sip->status = g_strdup("busy"); | |
| 119 | |
| 120 do_notifies(sip); | |
| 121 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
122 if ((primitive != GAIM_STATUS_OFFLINE) |
| 11181 | 123 && (!gaim_account_is_connected(account))) { |
| 124 gaim_account_connect(account); | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 static struct sip_connection *connection_find(struct simple_account_data *sip, int fd) { | |
| 129 struct sip_connection *ret = NULL; | |
| 130 GSList *entry = sip->openconns; | |
| 131 while(entry) { | |
| 132 ret = entry->data; | |
| 133 if(ret->fd == fd) return ret; | |
| 134 entry = entry->next; | |
| 135 } | |
| 136 return NULL; | |
| 137 } | |
| 138 | |
| 139 static struct simple_watcher *watcher_find(struct simple_account_data *sip, gchar *name) { | |
| 140 struct simple_watcher *watcher; | |
| 141 GSList *entry = sip->watcher; | |
| 142 while(entry) { | |
| 143 watcher = entry->data; | |
| 144 if(!strcmp(name, watcher->name)) return watcher; | |
| 145 entry = entry->next; | |
| 146 } | |
| 147 return NULL; | |
| 148 } | |
| 149 | |
| 150 static struct simple_watcher *watcher_create(struct simple_account_data *sip, gchar *name, gchar *callid, gchar *ourtag, gchar *theirtag) { | |
| 151 struct simple_watcher *watcher = g_new0(struct simple_watcher,1); | |
| 152 watcher->name = g_strdup(name); | |
| 153 watcher->dialog.callid = g_strdup(callid); | |
| 154 watcher->dialog.ourtag = g_strdup(ourtag); | |
| 155 watcher->dialog.theirtag = g_strdup(theirtag); | |
| 156 sip->watcher = g_slist_append(sip->watcher, watcher); | |
| 157 return watcher; | |
| 158 } | |
| 159 | |
| 160 static void watcher_remove(struct simple_account_data *sip, gchar *name) { | |
| 161 struct simple_watcher *watcher = watcher_find(sip, name); | |
| 162 sip->watcher = g_slist_remove(sip->watcher, watcher); | |
| 163 g_free(watcher->name); | |
| 164 g_free(watcher->dialog.callid); | |
| 165 g_free(watcher->dialog.ourtag); | |
| 166 g_free(watcher->dialog.theirtag); | |
| 167 g_free(watcher); | |
| 168 } | |
| 169 | |
| 170 static struct sip_connection *connection_create(struct simple_account_data *sip, int fd) { | |
| 171 struct sip_connection *ret = g_new0(struct sip_connection,1); | |
| 172 ret->fd = fd; | |
| 173 sip->openconns = g_slist_append(sip->openconns, ret); | |
| 174 return ret; | |
| 175 } | |
| 176 | |
| 177 static void connection_remove(struct simple_account_data *sip, int fd) { | |
| 178 struct sip_connection *conn = connection_find(sip, fd); | |
| 179 sip->openconns = g_slist_remove(sip->openconns, conn); | |
| 180 if(conn->inputhandler) gaim_input_remove(conn->inputhandler); | |
| 181 if(conn->inbuf) g_free(conn->inbuf); | |
| 182 g_free(conn); | |
| 183 } | |
| 184 | |
| 11346 | 185 static void connection_free_all(struct simple_account_data *sip) { |
| 186 struct sip_connection *ret = NULL; | |
| 187 GSList *entry = sip->openconns; | |
| 188 while(entry) { | |
| 189 ret = entry->data; | |
| 190 connection_remove(sip, ret->fd); | |
| 191 entry = sip->openconns; | |
| 192 } | |
| 193 } | |
| 194 | |
| 11181 | 195 static void simple_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group) |
| 196 { | |
| 197 struct simple_account_data *sip = (struct simple_account_data *)gc->proto_data; | |
| 198 struct simple_buddy *b; | |
| 199 if(strncmp("sip:", buddy->name,4)) { | |
| 200 gchar *buf = g_strdup_printf(_("Could not add the buddy %s because every simple user has to start with 'sip:'."), buddy->name); | |
| 201 gaim_notify_error(gc, NULL, _("Unable To Add"), buf); | |
| 202 g_free(buf); | |
| 203 gaim_blist_remove_buddy(buddy); | |
| 204 return; | |
| 205 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
206 if(!g_hash_table_lookup(sip->buddies, buddy->name)) { |
| 11181 | 207 b = g_new0(struct simple_buddy, 1); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
208 gaim_debug_info("simple","simple_add_buddy %s\n",buddy->name); |
| 11181 | 209 b->name = g_strdup(buddy->name); |
| 210 g_hash_table_insert(sip->buddies, b->name, b); | |
| 211 } else { | |
| 212 gaim_debug_info("simple","buddy %s already in internal list\n", buddy->name); | |
| 213 } | |
| 214 } | |
| 215 | |
| 216 static void simple_get_buddies(GaimConnection *gc) { | |
| 217 GaimBlistNode *gnode, *cnode, *bnode; | |
| 218 | |
| 219 gaim_debug_info("simple","simple_get_buddies\n"); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
220 |
| 11181 | 221 for(gnode = gaim_get_blist()->root; gnode; gnode = gnode->next) { |
| 222 if(!GAIM_BLIST_NODE_IS_GROUP(gnode)) continue; | |
| 223 for(cnode = gnode->child; cnode; cnode = cnode->next) { | |
| 224 if(!GAIM_BLIST_NODE_IS_CONTACT(cnode)) continue; | |
| 225 for(bnode = cnode->child; bnode; bnode = bnode->next) { | |
| 226 if(!GAIM_BLIST_NODE_IS_BUDDY(bnode)) continue; | |
| 11192 | 227 if(((GaimBuddy*)bnode)->account == gc->account) |
| 228 simple_add_buddy(gc, (GaimBuddy*)bnode, (GaimGroup *)gnode); | |
| 11181 | 229 } |
| 230 } | |
| 231 } | |
| 232 } | |
| 233 | |
| 234 static void simple_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group) | |
| 235 { | |
| 236 struct simple_account_data *sip = (struct simple_account_data *)gc->proto_data; | |
| 237 struct simple_buddy *b = g_hash_table_lookup(sip->buddies, buddy->name); | |
| 238 g_hash_table_remove(sip->buddies, buddy->name); | |
| 239 g_free(b->name); | |
| 240 g_free(b); | |
| 241 } | |
| 242 | |
| 243 static GList *simple_status_types(GaimAccount *acc) { | |
| 244 GaimStatusType *type; | |
| 245 GList *types = NULL; | |
| 246 gaim_debug_info("simple","called simple_status_types\n"); | |
| 247 type = gaim_status_type_new(GAIM_STATUS_OFFLINE, "offline", _("Offline"), FALSE); | |
| 248 types = g_list_append(types, type); | |
| 249 | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
250 type = gaim_status_type_new_with_attrs( |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
251 GAIM_STATUS_AVAILABLE, "available", _("Available"), |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
252 TRUE, TRUE, FALSE, |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
253 "message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), NULL); |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
254 types = g_list_append(types, type); |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
255 |
| 11181 | 256 return types; |
| 257 } | |
| 258 | |
| 11346 | 259 static gchar *auth_header(struct simple_account_data *sip, struct sip_auth *auth, gchar *method, gchar *target) { |
| 260 gchar noncecount[9]; | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
261 HASHHEX HA2; |
| 11346 | 262 HASHHEX response; |
| 263 gchar *ret; | |
| 11409 | 264 gchar *tmp; |
| 265 | |
| 266 if(auth->type == 1) { /* Digest */ | |
| 267 sprintf(noncecount, "%08d", auth->nc++); | |
| 268 DigestCalcResponse(auth->HA1, auth->nonce, noncecount, "", "", method, target, HA2, response); | |
| 269 gaim_debug(GAIM_DEBUG_MISC, "simple", "response %s\n", response); | |
| 270 ret = g_strdup_printf("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", nc=\"%s\", response=\"%s\"\r\n",sip->username, auth->realm, auth->nonce, target, noncecount, response); | |
| 271 return ret; | |
| 272 } else if(auth->type == 2) { /* NTLM */ | |
| 273 if(auth->nc == 3) { | |
| 274 ret = gaim_ntlm_gen_type3(sip->username, sip->password, "gaim", sip->servername, auth->nonce); | |
| 11424 | 275 tmp = g_strdup_printf("NTLM qop=\"auth\" realm=\"%s\" targetname=\"%s\" response=\"%s\"\r\n",auth->realm, auth->target, ret); |
| 11409 | 276 g_free(ret); |
| 277 return tmp; | |
| 278 } | |
| 279 ret = gaim_ntlm_gen_type1("gaim", sip->servername); | |
| 11483 | 280 tmp = g_strdup_printf("NTLM qop=\"auth\" realm=\"%s\" targetname=\"%s\" response=\"%s\"\r\n", auth->realm, auth->target, ret); |
| 11409 | 281 g_free(ret); |
| 282 return tmp; | |
| 283 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
284 |
| 11346 | 285 sprintf(noncecount, "%08d", auth->nc++); |
| 286 DigestCalcResponse(auth->HA1, auth->nonce, noncecount, "", "", method, target, HA2, response); | |
| 287 gaim_debug(GAIM_DEBUG_MISC, "simple", "response %s\n", response); | |
| 288 ret = g_strdup_printf("Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", nc=\"%s\", response=\"%s\"\r\n",sip->username, auth->realm, auth->nonce, target, noncecount, response); | |
| 289 return ret; | |
| 290 } | |
| 291 | |
| 292 static void fill_auth(struct simple_account_data *sip, gchar *hdr, struct sip_auth *auth) { | |
| 11409 | 293 int i=0; |
| 11424 | 294 char *tmp; |
| 295 char *tmp2; | |
|
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
296 gchar **parts; |
| 11346 | 297 if(!hdr) { |
| 11409 | 298 gaim_debug_error("simple", "fill_auth: hdr==NULL\n"); |
| 11346 | 299 return; |
| 300 } | |
| 11409 | 301 |
| 302 if(!g_strncasecmp(hdr, "NTLM", 4)) { | |
| 303 gaim_debug_info("simple", "found NTLM\n"); | |
| 304 auth->type = 2; | |
| 305 if(!auth->nonce && !auth->nc) { | |
|
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
306 parts = g_strsplit(hdr, " ", 0); |
| 11424 | 307 while(parts[i]) { |
| 308 if(!strncmp(parts[i],"targetname",10)) { | |
| 309 auth->target = g_strndup(parts[i]+12,strlen(parts[i]+12)-1); | |
| 310 } | |
| 311 if(!strncmp(parts[i],"realm",5)) { | |
| 312 tmp = strstr(hdr, "realm="); | |
| 313 tmp += 7; | |
| 314 tmp2 = strchr(tmp, '"'); | |
| 315 *tmp2 = 0; | |
| 316 auth->realm = g_strdup(tmp); | |
| 317 *tmp2 = '"'; | |
| 318 } | |
| 319 i++; | |
| 320 } | |
|
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
321 g_strfreev(parts); |
|
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
322 parts = NULL; |
| 11409 | 323 auth->nc = 1; |
| 324 } | |
| 325 if(!auth->nonce && auth->nc==2) { | |
| 326 auth->nc = 3; | |
| 327 auth->nonce = gaim_ntlm_parse_type2(hdr+5); | |
| 328 } | |
| 329 return; | |
| 330 } | |
| 331 | |
| 332 auth->type = 1; | |
|
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
333 parts = g_strsplit(hdr, " ", 0); |
| 11346 | 334 while(parts[i]) { |
| 335 if(!strncmp(parts[i],"nonce",5)) { | |
| 336 auth->nonce = g_strndup(parts[i]+7,strlen(parts[i]+7)-1); | |
| 337 } | |
| 338 if(!strncmp(parts[i],"realm",5)) { | |
| 339 auth->realm = g_strndup(parts[i]+7,strlen(parts[i]+7)-2); | |
| 340 } | |
| 341 i++; | |
| 342 } | |
|
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
343 g_strfreev(parts); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
344 |
| 11346 | 345 gaim_debug(GAIM_DEBUG_MISC, "simple", "nonce: %s realm: %s ", auth->nonce, auth->realm); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
346 |
| 11346 | 347 DigestCalcHA1("md5", sip->username, auth->realm, sip->password, auth->nonce, "", auth->HA1); |
| 348 | |
| 349 auth->nc=1; | |
| 350 } | |
| 351 | |
| 11181 | 352 static void simple_input_cb(gpointer data, gint source, GaimInputCondition cond); |
| 353 | |
| 354 static void send_later_cb(gpointer data, gint source, GaimInputCondition cond) { | |
| 355 GaimConnection *gc = data; | |
| 356 struct simple_account_data *sip = gc->proto_data; | |
| 357 struct sip_connection *conn; | |
| 358 | |
| 359 if( source < 0 ) { | |
| 360 gaim_connection_error(gc,"Could not connect"); | |
| 361 return; | |
| 362 } | |
| 363 | |
| 364 sip->fd = source; | |
| 365 sip->connecting = 0; | |
| 366 write(sip->fd, sip->sendlater, strlen(sip->sendlater)); | |
| 367 conn = connection_create(sip, source); | |
| 368 conn->inputhandler = gaim_input_add(sip->fd, GAIM_INPUT_READ, simple_input_cb, gc); | |
| 369 g_free(sip->sendlater); | |
| 370 sip->sendlater = 0; | |
| 371 } | |
| 372 | |
| 373 | |
| 374 static void sendlater(GaimConnection *gc, const char *buf) { | |
| 375 struct simple_account_data *sip = gc->proto_data; | |
| 376 int error = 0; | |
| 377 if(!sip->connecting) { | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
378 gaim_debug_info("simple","connecting to %s port %d\n", sip->realhostname ? sip->realhostname : "{NULL}", sip->realport); |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
379 error = gaim_proxy_connect(sip->account, sip->realhostname, sip->realport, send_later_cb, gc); |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
380 if(error) { |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
381 gaim_connection_error(gc, _("Couldn't create socket")); |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
382 } |
| 11181 | 383 sip->connecting = 1; |
| 384 } | |
| 385 if(sip->sendlater) { | |
| 386 gchar *old = sip->sendlater; | |
| 387 sip->sendlater = g_strdup_printf("%s\r\n%s",old, buf); | |
| 388 } else { | |
| 389 sip->sendlater = g_strdup(buf); | |
| 390 } | |
| 391 } | |
| 392 | |
| 393 static int sendout_pkt(GaimConnection *gc, const char *buf) { | |
| 394 struct simple_account_data *sip = gc->proto_data; | |
| 395 time_t currtime = time(NULL); | |
| 11189 | 396 int ret = 0; |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
397 |
| 11181 | 398 gaim_debug(GAIM_DEBUG_MISC, "simple", "\n\nsending - %s\n######\n%s\n######\n\n", ctime(&currtime), buf); |
| 11189 | 399 if(sip->udp) { |
| 400 if(sendto(sip->fd, buf, strlen(buf), 0, (struct sockaddr*)&sip->serveraddr, sizeof(struct sockaddr_in)) < strlen(buf)) { | |
| 401 gaim_debug_info("simple", "could not send packet\n"); | |
| 402 } | |
| 403 } else { | |
| 404 if(sip->fd <0 ) { | |
| 405 sendlater(gc, buf); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
406 return 0; |
| 11189 | 407 } |
| 408 ret = write(sip->fd, buf, strlen(buf)); | |
| 409 if(ret < 0) { | |
| 410 sendlater(gc,buf); | |
| 411 return 0; | |
| 412 } | |
| 11181 | 413 } |
| 414 return ret; | |
| 415 } | |
| 416 | |
| 11194 | 417 static void sendout_sipmsg(struct simple_account_data *sip, struct sipmsg *msg) { |
| 418 gchar *oldstr; | |
| 419 gchar *outstr = g_strdup_printf("%s %s SIP/2.0\r\n", msg->method, msg->target); | |
| 420 gchar *name; | |
| 421 gchar *value; | |
| 422 GSList *tmp = msg->headers; | |
| 423 while(tmp) { | |
| 424 oldstr = outstr; | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
425 name = ((struct siphdrelement*)(tmp->data))->name; |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
426 value = ((struct siphdrelement*)(tmp->data))->value; |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
427 outstr = g_strdup_printf("%s%s: %s\r\n",oldstr, name, value); |
| 11194 | 428 g_free(oldstr); |
| 429 tmp = g_slist_next(tmp); | |
| 430 } | |
| 431 oldstr = outstr; | |
| 432 if(msg->body) outstr = g_strdup_printf("%s\r\n%s", outstr, msg->body); | |
| 433 else outstr = g_strdup_printf("%s\r\n", outstr); | |
| 434 g_free(oldstr); | |
| 435 sendout_pkt(sip->gc, outstr); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
436 g_free(outstr); |
| 11194 | 437 } |
| 438 | |
| 11181 | 439 static void send_sip_response(GaimConnection *gc, struct sipmsg *msg, int code, char *text, char *body) { |
| 440 GSList *tmp = msg->headers; | |
| 441 char *oldstr; | |
| 442 char *name; | |
| 443 char *value; | |
| 444 char *outstr = g_strdup_printf("SIP/2.0 %d %s\r\n",code, text); | |
| 445 while(tmp) { | |
| 446 oldstr = outstr; | |
| 447 name = ((struct siphdrelement*)(tmp->data))->name; | |
| 448 value = ((struct siphdrelement*)(tmp->data))->value; | |
| 449 outstr = g_strdup_printf("%s%s: %s\r\n",oldstr, name, value); | |
| 450 g_free(oldstr); | |
| 451 tmp = g_slist_next(tmp); | |
| 452 } | |
| 453 oldstr = outstr; | |
| 454 if(body) outstr = g_strdup_printf("%s\r\n%s",outstr,body); | |
| 455 else outstr = g_strdup_printf("%s\r\n",outstr); | |
| 456 g_free(oldstr); | |
| 457 sendout_pkt(gc, outstr); | |
| 458 g_free(outstr); | |
| 459 } | |
| 460 | |
| 11194 | 461 static void transactions_remove(struct simple_account_data *sip, struct transaction *trans) { |
| 462 if(trans->msg) sipmsg_free(trans->msg); | |
| 463 sip->transactions = g_slist_remove(sip->transactions, trans); | |
| 464 g_free(trans); | |
| 465 } | |
| 466 | |
| 11181 | 467 static void transactions_add_buf(struct simple_account_data *sip, gchar *buf, void *callback) { |
| 468 struct transaction *trans = g_new0(struct transaction, 1); | |
| 469 trans->time = time(NULL); | |
| 470 trans->msg = sipmsg_parse_msg(buf); | |
| 471 trans->cseq = sipmsg_find_header(trans->msg, "CSeq"); | |
| 472 trans->callback = callback; | |
| 473 sip->transactions = g_slist_append(sip->transactions, trans); | |
| 474 } | |
| 475 | |
| 476 static struct transaction *transactions_find(struct simple_account_data *sip, struct sipmsg *msg) { | |
| 477 struct transaction *trans; | |
| 478 GSList *transactions = sip->transactions; | |
| 479 gchar *cseq = sipmsg_find_header(msg, "CSeq"); | |
| 480 | |
| 481 while(transactions) { | |
| 482 trans = transactions->data; | |
| 483 if(!strcmp(trans->cseq, cseq)) { | |
| 484 return trans; | |
| 485 } | |
| 486 transactions = transactions->next; | |
| 487 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
488 |
| 11181 | 489 return (struct transaction *)NULL; |
| 490 } | |
| 491 | |
| 492 static void send_sip_request(GaimConnection *gc, gchar *method, gchar *url, gchar *to, gchar *addheaders, gchar *body, struct sip_dialog *dialog, TransCallback tc) { | |
| 493 struct simple_account_data *sip = gc->proto_data; | |
| 494 char *callid= dialog ? g_strdup(dialog->callid) : gencallid(); | |
| 495 char *auth=""; | |
| 496 char *addh=""; | |
| 497 gchar *branch = genbranch(); | |
| 498 char *buf; | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
499 |
| 11181 | 500 if(addheaders) addh=addheaders; |
| 11409 | 501 if(sip->registrar.type && !strcmp(method,"REGISTER")) { |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
502 buf = auth_header(sip, &sip->registrar, method, url); |
| 11346 | 503 auth = g_strdup_printf("Authorization: %s",buf); |
| 504 g_free(buf); | |
| 11181 | 505 gaim_debug(GAIM_DEBUG_MISC, "simple", "header %s", auth); |
| 506 } | |
| 507 | |
| 11409 | 508 if(sip->proxy.type && strcmp(method,"REGISTER")) { |
| 11346 | 509 buf = auth_header(sip, &sip->proxy, method, url); |
| 510 auth = g_strdup_printf("Proxy-Authorization: %s",buf); | |
| 511 g_free(buf); | |
| 11181 | 512 gaim_debug(GAIM_DEBUG_MISC, "simple", "header %s", auth); |
| 513 } | |
| 514 | |
| 515 buf = g_strdup_printf("%s %s SIP/2.0\r\n" | |
| 11190 | 516 "Via: SIP/2.0/%s %s:%d;branch=%s\r\n" |
| 11181 | 517 "From: <sip:%s@%s>;tag=%s\r\n" |
| 518 "To: <%s>%s%s\r\n" | |
| 519 "Max-Forwards: 10\r\n" | |
| 520 "CSeq: %d %s\r\n" | |
| 521 "User-Agent: Gaim SIP/SIMPLE Plugin\r\n" | |
| 522 "Call-ID: %s\r\n" | |
| 523 "%s%s" | |
| 524 "Content-Length: %d\r\n\r\n%s", | |
| 525 method, | |
| 526 url, | |
| 11190 | 527 sip->udp ? "UDP" : "TCP", |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
528 sip->ip ? sip->ip : "", |
| 11181 | 529 sip->listenport, |
| 530 branch, | |
| 531 sip->username, | |
| 532 sip->servername, | |
| 533 dialog ? dialog->ourtag : gentag(), | |
| 534 to, | |
| 535 dialog ? ";tag=" : "", | |
| 536 dialog ? dialog->theirtag : "", | |
| 537 ++sip->cseq, | |
| 538 method, | |
| 539 callid, | |
| 540 auth, | |
| 541 addh, | |
| 542 strlen(body), | |
| 543 body); | |
| 544 g_free(branch); | |
| 545 g_free(callid); | |
| 546 | |
| 11341 | 547 /* add to ongoing transactions */ |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
548 |
| 11181 | 549 transactions_add_buf(sip, buf, tc); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
550 |
| 11181 | 551 sendout_pkt(gc,buf); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
552 |
| 11181 | 553 g_free(buf); |
| 554 } | |
| 555 | |
| 11194 | 556 static void do_register_exp(struct simple_account_data *sip, int expire) { |
| 11181 | 557 char *uri = g_strdup_printf("sip:%s",sip->servername); |
| 558 char *to = g_strdup_printf("sip:%s@%s",sip->username,sip->servername); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
559 char *contact = g_strdup_printf("Contact: <sip:%s@%s:%d;transport=%s>;methods=\"MESSAGE, SUBSCRIBE, NOTIFY\"\r\nExpires: %d\r\n", sip->username, sip->ip ? sip->ip : "", sip->listenport, sip->udp ? "udp" : "tcp", expire); |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
560 |
|
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
561 sip->registerstatus = 1; |
|
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
562 |
| 11194 | 563 if(expire) { |
| 564 sip->reregister = time(NULL) + expire - 50; | |
| 565 } else { | |
| 566 sip->reregister = time(NULL) + 600; | |
| 567 } | |
| 568 send_sip_request(sip->gc,"REGISTER",uri,to, contact, "", NULL, process_register_response); | |
| 11341 | 569 g_free(contact); |
| 11181 | 570 g_free(uri); |
| 571 g_free(to); | |
| 572 } | |
| 573 | |
| 11194 | 574 static void do_register(struct simple_account_data *sip) { |
| 575 do_register_exp(sip, sip->registerexpire); | |
| 576 } | |
| 577 | |
| 11181 | 578 static gchar *parse_from(gchar *hdr) { |
| 579 gchar *from = hdr; | |
| 580 gchar *tmp; | |
| 581 | |
| 582 if(!from) return NULL; | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
583 gaim_debug_info("simple", "parsing address out of %s\n",from); |
| 11181 | 584 tmp = strchr(from, '<'); |
| 585 | |
| 11341 | 586 /* i hate the different SIP UA behaviours... */ |
| 587 if(tmp) { /* sip address in <...> */ | |
| 11181 | 588 from = tmp+1; |
| 589 tmp = strchr(from,'>'); | |
| 590 if(tmp) { | |
| 591 from = g_strndup(from,tmp-from); | |
| 592 } else { | |
| 593 gaim_debug_info("simple", "found < without > in From\n"); | |
| 594 return NULL; | |
| 595 } | |
| 596 } else { | |
| 597 tmp = strchr(from, ';'); | |
| 598 if(tmp) { | |
| 599 from = g_strndup(from,tmp-from); | |
| 11483 | 600 } else { |
| 601 from = g_strdup(from); | |
| 11181 | 602 } |
| 603 } | |
| 604 gaim_debug_info("simple", "got %s\n",from); | |
| 605 return from; | |
| 606 } | |
| 607 | |
| 608 static gboolean process_subscribe_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { | |
| 11341 | 609 gchar *to = parse_from(sipmsg_find_header(tc->msg,"To")); /* cant be NULL since it is our own msg */ |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
610 |
| 11181 | 611 if(msg->response==200 || msg->response==202) { |
| 612 return TRUE; | |
| 613 } | |
| 614 | |
| 11341 | 615 /* we can not subscribe -> user is offline (TODO unknown status?) */ |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
616 |
| 11181 | 617 gaim_prpl_got_user_status(sip->account, to, "offline", NULL); |
| 618 g_free(to); | |
| 619 return TRUE; | |
| 620 } | |
| 621 | |
| 622 static void simple_subscribe(struct simple_account_data *sip, struct simple_buddy *buddy) { | |
| 11341 | 623 gchar *contact = "Expires: 300\r\nAccept: application/pidf+xml\r\nEvent: presence\r\n"; |
| 11181 | 624 gchar *to; |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
625 if(strstr(buddy->name,"sip:")) to = g_strdup(buddy->name); |
| 11181 | 626 else to = g_strdup_printf("sip:%s",buddy->name); |
| 11341 | 627 contact = g_strdup_printf("%sContact: <%s@%s>\r\n", contact, sip->username, sip->servername); |
| 628 /* subscribe to buddy presence | |
| 629 * we dont need to know the status so we do not need a callback */ | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
630 |
| 11181 | 631 send_sip_request(sip->gc, "SUBSCRIBE",to, to, contact, "", NULL, process_subscribe_response); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
632 |
| 11181 | 633 g_free(to); |
| 11341 | 634 g_free(contact); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
635 |
| 11341 | 636 /* resubscribe before subscription expires */ |
| 637 /* add some jitter */ | |
| 638 buddy->resubscribe = time(NULL)+250+(rand()%50); | |
| 11181 | 639 } |
| 640 | |
| 641 static void simple_buddy_resub(char *name, struct simple_buddy *buddy, struct simple_account_data *sip) { | |
| 642 time_t curtime = time(NULL); | |
| 11341 | 643 gaim_debug_info("simple","buddy resub\n"); |
| 11181 | 644 if(buddy->resubscribe < curtime) { |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
645 gaim_debug(GAIM_DEBUG_MISC, "simple", "simple_buddy_resub %s\n",name); |
| 11181 | 646 simple_subscribe(sip, buddy); |
| 647 } | |
| 648 } | |
| 649 | |
| 11194 | 650 static gboolean resend_timeout(struct simple_account_data *sip) { |
| 651 GSList *tmp = sip->transactions; | |
| 652 time_t currtime = time(NULL); | |
| 653 while(tmp) { | |
| 654 struct transaction *trans = tmp->data; | |
| 655 tmp = tmp->next; | |
| 656 gaim_debug_info("simple", "have open transaction age: %d\n", currtime- trans->time); | |
| 657 if((currtime - trans->time > 5) && trans->retries >= 1) { | |
| 11341 | 658 /* TODO 408 */ |
| 11194 | 659 } else { |
| 660 if((currtime - trans->time > 2) && trans->retries == 0) { | |
| 661 trans->retries++; | |
| 662 sendout_sipmsg(sip, trans->msg); | |
| 663 } | |
| 664 } | |
| 665 } | |
| 666 return TRUE; | |
| 667 } | |
| 668 | |
| 11181 | 669 static gboolean register_timeout(struct simple_account_data *sip) { |
| 670 GSList *tmp; | |
| 671 time_t curtime = time(NULL); | |
| 11341 | 672 /* register again if first registration expires */ |
| 11181 | 673 if(sip->reregister < curtime) { |
| 11194 | 674 do_register(sip); |
| 11181 | 675 } |
| 11341 | 676 gaim_debug_info("simple","in register timeout\n"); |
| 677 /* check for every subscription if we need to resubscribe */ | |
| 11181 | 678 g_hash_table_foreach(sip->buddies, (GHFunc)simple_buddy_resub, (gpointer)sip); |
| 679 | |
| 11341 | 680 /* remove a timed out suscriber */ |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
681 |
| 11181 | 682 tmp = sip->watcher; |
| 683 while(tmp) { | |
| 684 struct simple_watcher *watcher = tmp->data; | |
| 685 if(watcher->expire < curtime) { | |
| 686 watcher_remove(sip, watcher->name); | |
| 687 tmp = sip->watcher; | |
| 688 } | |
| 689 if(tmp) tmp = tmp->next; | |
| 690 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
691 |
| 11181 | 692 return TRUE; |
| 693 } | |
| 694 | |
| 695 static void simple_send_message(struct simple_account_data *sip, char *to, char *msg, char *type) { | |
| 696 gchar *hdr; | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
697 if(type) { |
| 11181 | 698 hdr = g_strdup_printf("Content-Type: %s\r\n",type); |
| 699 } else { | |
| 700 hdr = g_strdup("Content-Type: text/plain\r\n"); | |
| 701 } | |
| 702 send_sip_request(sip->gc, "MESSAGE", to, to, hdr, msg, NULL, NULL); | |
| 703 g_free(hdr); | |
| 704 } | |
| 705 | |
| 706 static int simple_im_send(GaimConnection *gc, const char *who, const char *what, GaimConvImFlags flags) { | |
| 707 struct simple_account_data *sip = gc->proto_data; | |
| 708 char *to = g_strdup(who); | |
| 709 char *text = g_strdup(what); | |
| 710 simple_send_message(sip, to, text, NULL); | |
| 711 g_free(to); | |
| 712 g_free(text); | |
| 713 return 1; | |
| 714 } | |
| 715 | |
| 716 static void process_incoming_message(struct simple_account_data *sip, struct sipmsg *msg) { | |
| 717 gchar *from; | |
| 718 gchar *contenttype; | |
| 719 gboolean found = FALSE; | |
| 720 | |
| 721 from = parse_from(sipmsg_find_header(msg, "From")); | |
| 722 | |
| 723 if(!from) return; | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
724 |
| 11181 | 725 gaim_debug(GAIM_DEBUG_MISC, "simple", "got message from %s: %s\n", from, msg->body); |
| 726 | |
| 727 contenttype = sipmsg_find_header(msg, "Content-Type"); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
728 if(!contenttype || !strncmp(contenttype, "text/plain", 10) || !strncmp(contenttype, "text/html", 9)) { |
| 11181 | 729 serv_got_im(sip->gc, from, msg->body, 0, time(NULL)); |
| 730 send_sip_response(sip->gc, msg, 200, "OK", NULL); | |
| 731 found = TRUE; | |
| 732 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
733 if(!strncmp(contenttype, "application/im-iscomposing+xml",30)) { |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
734 xmlnode *isc = xmlnode_from_str(msg->body, msg->bodylen); |
| 11181 | 735 xmlnode *state; |
| 736 gchar *statedata; | |
| 737 | |
| 738 if(!isc) { | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
739 gaim_debug_info("simple","process_incoming_message: can not parse iscomposing\n"); |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
740 return; |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
741 } |
| 11181 | 742 |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
743 state = xmlnode_get_child(isc, "state"); |
| 11181 | 744 |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
745 if(!state) { |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
746 gaim_debug_info("simple","process_incoming_message: no state found\n"); |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
747 return; |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
748 } |
| 11181 | 749 |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
750 statedata = xmlnode_get_data(state); |
| 11181 | 751 if(statedata) { |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
752 if(strstr(statedata,"active")) serv_got_typing(sip->gc, from, 0, GAIM_TYPING); |
| 11181 | 753 else serv_got_typing_stopped(sip->gc, from); |
| 754 } | |
| 755 xmlnode_free(isc); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
756 send_sip_response(sip->gc, msg, 200, "OK", NULL); |
| 11181 | 757 found = TRUE; |
| 758 } | |
| 759 if(!found) { | |
| 760 gaim_debug_info("simple", "got unknown mime-type"); | |
| 761 send_sip_response(sip->gc, msg, 415, "Unsupported media type", NULL); | |
| 762 } | |
| 763 g_free(from); | |
| 764 } | |
| 765 | |
| 766 | |
| 767 gboolean process_register_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { | |
| 768 gchar *tmp; | |
| 769 gaim_debug(GAIM_DEBUG_MISC, "simple", "in process register response response: %d\n", msg->response); | |
| 770 switch (msg->response) { | |
| 771 case 200: | |
| 11341 | 772 if(sip->registerstatus<3) { /* registered */ |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
773 if(gaim_account_get_bool(sip->account, "dopublish", TRUE)) { |
| 11345 | 774 send_publish(sip); |
| 775 } | |
| 11181 | 776 } |
| 777 sip->registerstatus=3; | |
| 778 gaim_connection_set_state(sip->gc, GAIM_CONNECTED); | |
| 11341 | 779 |
| 780 /* get buddies from blist */ | |
| 781 simple_get_buddies(sip->gc); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
782 |
| 11181 | 783 register_timeout(sip); |
| 784 break; | |
| 785 case 401: | |
| 786 if(sip->registerstatus!=2) { | |
| 11346 | 787 gaim_debug_info("simple","REGISTER retries %d\n",sip->registrar.retries); |
| 788 if(sip->registrar.retries>3) { | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
789 gaim_connection_error(sip->gc,"Wrong Password"); |
| 11346 | 790 return TRUE; |
| 791 } | |
| 11181 | 792 tmp = sipmsg_find_header(msg, "WWW-Authenticate"); |
| 793 fill_auth(sip, tmp, &sip->registrar); | |
| 794 sip->registerstatus=2; | |
| 11194 | 795 do_register(sip); |
| 11181 | 796 } |
| 797 break; | |
| 798 } | |
| 799 return TRUE; | |
| 800 } | |
| 801 | |
| 802 static void process_incoming_notify(struct simple_account_data *sip, struct sipmsg *msg) { | |
| 803 gchar *from; | |
| 804 gchar *fromhdr; | |
| 805 gchar *tmp2; | |
| 806 xmlnode *pidf; | |
| 807 xmlnode *basicstatus; | |
| 808 gboolean isonline = FALSE; | |
| 809 | |
| 810 fromhdr = sipmsg_find_header(msg,"From"); | |
| 811 from = parse_from(fromhdr); | |
| 812 if(!from) return; | |
| 813 | |
| 814 pidf = xmlnode_from_str(msg->body, msg->bodylen); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
815 |
| 11181 | 816 if(!pidf) { |
| 817 gaim_debug_info("simple","process_incoming_notify: no parseable pidf\n"); | |
| 818 return; | |
| 819 } | |
| 820 | |
| 821 basicstatus = xmlnode_get_child(xmlnode_get_child(xmlnode_get_child(pidf,"tuple"),"status"), "basic"); | |
| 822 | |
| 823 if(!basicstatus) { | |
| 824 gaim_debug_info("simple","process_incoming_notify: no basic found\n"); | |
| 825 return; | |
| 826 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
827 |
| 11181 | 828 tmp2 = xmlnode_get_data(basicstatus); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
829 |
| 11181 | 830 if(!tmp2) { |
| 831 gaim_debug_info("simple","process_incoming_notify: no basic data found\n"); | |
| 832 return; | |
| 833 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
834 |
| 11181 | 835 if(strstr(tmp2, "open")) { |
| 836 isonline = TRUE; | |
| 837 } | |
| 838 | |
| 839 if(isonline) gaim_prpl_got_user_status(sip->account, from, "available", NULL); | |
| 840 else gaim_prpl_got_user_status(sip->account, from, "offline", NULL); | |
| 841 | |
| 842 xmlnode_free(pidf); | |
| 843 | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
844 g_free(from); |
| 11181 | 845 send_sip_response(sip->gc, msg, 200, "OK", NULL); |
| 846 } | |
| 847 | |
| 848 static int simple_typing(GaimConnection *gc, const char *name, int typing) { | |
| 849 struct simple_account_data *sip = gc->proto_data; | |
| 850 | |
| 851 gchar *xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" | |
| 852 "<isComposing xmlns=\"urn:ietf:params:xml:ns:im-iscomposing\"\n" | |
| 853 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" | |
| 854 "xsi:schemaLocation=\"urn:ietf:params:xml:ns:im-composing iscomposing.xsd\">\n" | |
| 855 "<state>%s</state>\n" | |
| 856 "<contenttype>text/plain</contenttype>\n" | |
| 857 "<refresh>60</refresh>\n" | |
| 858 "</isComposing>"; | |
| 859 gchar *recv = g_strdup(name); | |
| 860 if(typing == GAIM_TYPING) { | |
| 861 gchar *msg = g_strdup_printf(xml, "active"); | |
| 862 simple_send_message(sip, recv, msg, "application/im-iscomposing+xml"); | |
| 863 g_free(msg); | |
| 864 } else { | |
| 865 gchar *msg = g_strdup_printf(xml, "idle"); | |
| 866 simple_send_message(sip, recv, msg, "application/im-iscomposing+xml"); | |
| 867 g_free(msg); | |
| 868 } | |
| 869 g_free(recv); | |
| 870 return 1; | |
| 871 } | |
| 872 | |
| 873 static gchar *find_tag(gchar *hdr) { | |
| 874 gchar *tmp = strstr(hdr, ";tag="); | |
| 875 gchar *tmp2; | |
| 876 if(!tmp) return NULL; | |
| 877 tmp += 5; | |
| 878 if((tmp2 = strchr(tmp, ';'))) { | |
| 879 tmp2[0] = '\0'; | |
| 880 tmp = g_strdup(tmp); | |
| 881 tmp2[0] = ';'; | |
| 882 return tmp; | |
| 883 } | |
| 884 return g_strdup(tmp); | |
| 885 } | |
| 886 | |
| 887 static gchar* gen_pidf(struct simple_account_data *sip) { | |
| 888 gchar *doc = g_strdup_printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
889 "<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n" |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
890 "xmlns:im=\"urn:ietf:params:xml:ns:pidf:im\"\n" |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
891 "entity=\"sip:%s@%s\">\n" |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
892 "<tuple id=\"bs35r9f\">\n" |
| 11181 | 893 "<status>\n" |
| 894 "<basic>open</basic>\n" | |
| 895 "<im:im>%s</im:im>\n" | |
| 896 "</status>\n" | |
| 897 "</tuple>\n" | |
| 898 "</presence>", | |
| 899 sip->username, | |
| 900 sip->servername, | |
| 901 sip->status); | |
| 902 return doc; | |
| 903 } | |
| 904 | |
| 905 static void send_notify(struct simple_account_data *sip, struct simple_watcher *watcher) { | |
| 906 gchar *doc = gen_pidf(sip); | |
| 907 send_sip_request(sip->gc, "NOTIFY", watcher->name, watcher->name, "Event: presence\r\nContent-Type: application/pidf+xml\r\n", doc, &watcher->dialog, NULL); | |
| 908 g_free(doc); | |
| 909 } | |
| 910 | |
| 911 static gboolean process_publish_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { | |
| 11345 | 912 if(msg->response != 200 && msg->response != 408) { |
| 11341 | 913 /* never send again */ |
| 11181 | 914 sip->republish = -1; |
| 915 } | |
| 916 return TRUE; | |
| 917 } | |
| 918 | |
| 919 static void send_publish(struct simple_account_data *sip) { | |
| 920 gchar *uri = g_strdup_printf("sip:%s@%s", sip->username, sip->servername); | |
| 921 gchar *doc = gen_pidf(sip); | |
| 11341 | 922 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); |
| 11181 | 923 sip->republish = time(NULL) + 500; |
| 924 g_free(doc); | |
| 925 } | |
| 926 | |
| 927 static void process_incoming_subscribe(struct simple_account_data *sip, struct sipmsg *msg) { | |
| 928 gchar *from = parse_from(sipmsg_find_header(msg, "From")); | |
| 929 gchar *theirtag = find_tag(sipmsg_find_header(msg, "From")); | |
| 930 gchar *ourtag = find_tag(sipmsg_find_header(msg, "To")); | |
| 931 gboolean tagadded = FALSE; | |
| 932 gchar *callid = sipmsg_find_header(msg, "Call-ID"); | |
| 933 gchar *expire = sipmsg_find_header(msg, "Expire"); | |
| 934 gchar *tmp; | |
| 935 struct simple_watcher *watcher = watcher_find(sip, from); | |
| 936 if(!ourtag) { | |
| 937 tagadded = TRUE; | |
| 938 ourtag = gentag(); | |
| 939 } | |
| 11341 | 940 if(!watcher) { /* new subscription */ |
| 11345 | 941 if(!gaim_privacy_check(sip->account, from)) { |
| 942 send_sip_response(sip->gc, msg, 202, "Ok", NULL); | |
| 943 goto privend; | |
| 944 } | |
| 11181 | 945 watcher = watcher_create(sip, from, callid, ourtag, theirtag); |
| 946 } | |
| 947 if(tagadded) { | |
| 948 gchar *to = g_strdup_printf("%s;tag=%s", sipmsg_find_header(msg, "To"), ourtag); | |
| 949 sipmsg_remove_header(msg, "To"); | |
| 950 sipmsg_add_header(msg, "To", to); | |
| 951 } | |
| 952 if(expire) | |
| 953 watcher->expire = time(NULL) + strtol(expire, NULL, 10); | |
| 954 else | |
| 955 watcher->expire = time(NULL) + 600; | |
| 956 sipmsg_remove_header(msg, "Contact"); | |
| 957 tmp = g_strdup_printf("<%s@%s>",sip->username, sip->servername); | |
| 958 sipmsg_add_header(msg, "Contact", tmp); | |
| 959 gaim_debug_info("simple","got subscribe: name %s ourtag %s theirtag %s callid %s\n", watcher->name, watcher->dialog.ourtag, watcher->dialog.theirtag, watcher->dialog.callid); | |
| 960 send_sip_response(sip->gc, msg, 200, "Ok", NULL); | |
| 961 g_free(tmp); | |
| 962 send_notify(sip, watcher); | |
| 11345 | 963 privend: |
| 964 g_free(from); | |
| 965 g_free(theirtag); | |
| 966 g_free(ourtag); | |
| 967 g_free(callid); | |
| 968 g_free(expire); | |
| 11181 | 969 } |
| 970 | |
| 11189 | 971 static void process_input_message(struct simple_account_data *sip, struct sipmsg *msg) { |
| 972 int found = 0; | |
| 11341 | 973 if( msg->response == 0 ) { /* request */ |
| 11189 | 974 if(!strcmp(msg->method, "MESSAGE")) { |
| 975 process_incoming_message(sip, msg); | |
| 976 found = 1; | |
| 977 } | |
| 978 if(!strcmp(msg->method, "NOTIFY")) { | |
| 979 process_incoming_notify(sip, msg); | |
| 980 found = 1; | |
| 981 } | |
| 982 if(!strcmp(msg->method, "SUBSCRIBE")) { | |
| 983 process_incoming_subscribe(sip, msg); | |
| 984 found = 1; | |
| 985 } | |
| 11190 | 986 if(!found) { |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
987 send_sip_response(sip->gc, msg, 501, "Not implemented", NULL); |
| 11190 | 988 } |
| 11341 | 989 } else { /* response */ |
| 11189 | 990 struct transaction *trans = transactions_find(sip, msg); |
| 991 if(trans) { | |
| 992 if(msg->response == 407) { | |
|
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
993 gchar *resend, *auth, *ptmp; |
|
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
994 |
| 11346 | 995 if(sip->proxy.retries>3) return; |
| 996 sip->proxy.retries++; | |
| 11341 | 997 /* do proxy authentication */ |
| 11189 | 998 |
|
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
999 ptmp = sipmsg_find_header(msg, "Proxy-Authenticate"); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1000 |
| 11189 | 1001 fill_auth(sip, ptmp, &sip->proxy); |
| 11346 | 1002 auth = auth_header(sip, &sip->proxy, trans->msg->method, trans->msg->target); |
| 11189 | 1003 sipmsg_remove_header(msg, "Proxy-Authorization"); |
| 1004 sipmsg_add_header(trans->msg, "Proxy-Authorization", auth); | |
| 1005 g_free(auth); | |
| 1006 resend = sipmsg_to_string(trans->msg); | |
| 11341 | 1007 /* resend request */ |
| 11189 | 1008 sendout_pkt(sip->gc, resend); |
| 1009 g_free(resend); | |
| 1010 } else { | |
| 11517 | 1011 if(msg->response == 100) { |
| 1012 /* ignore provisional response */ | |
| 1013 gaim_debug_info("simple","got trying response\n"); | |
| 1014 } else { | |
| 1015 sip->proxy.retries = 0; | |
| 1016 if(msg->response == 401) sip->registrar.retries++; | |
| 1017 else sip->registrar.retries = 0; | |
| 1018 if(trans->callback) { | |
| 1019 /* call the callback to process response*/ | |
| 1020 (trans->callback)(sip, msg, trans); | |
| 1021 } | |
| 1022 transactions_remove(sip, trans); | |
| 11189 | 1023 } |
| 1024 } | |
| 1025 found = 1; | |
| 1026 } else { | |
| 1027 gaim_debug(GAIM_DEBUG_MISC, "simple", "received response to unknown transaction"); | |
| 1028 } | |
| 1029 } | |
| 1030 if(!found) { | |
| 1031 gaim_debug(GAIM_DEBUG_MISC, "simple", "received a unknown sip message with method %sand response %d\n",msg->method, msg->response); | |
| 1032 } | |
| 1033 } | |
| 1034 | |
| 11181 | 1035 static void process_input(struct simple_account_data *sip, struct sip_connection *conn) |
| 1036 { | |
| 1037 char *cur; | |
| 1038 char *dummy; | |
| 1039 struct sipmsg *msg; | |
| 1040 int restlen; | |
| 1041 cur = conn->inbuf; | |
| 1042 | |
| 11341 | 1043 /* according to the RFC remove CRLF at the beginning */ |
| 11181 | 1044 while(*cur == '\r' || *cur == '\n') { |
| 1045 cur++; | |
| 1046 } | |
| 1047 if(cur != conn->inbuf) { | |
| 1048 memmove(conn->inbuf, cur, conn->inbufused-(cur-conn->inbuf)); | |
| 1049 conn->inbufused=strlen(conn->inbuf); | |
| 1050 } | |
| 1051 | |
| 11341 | 1052 /* Received a full Header? */ |
| 11181 | 1053 if((cur = strstr(conn->inbuf, "\r\n\r\n"))!=NULL) { |
| 1054 time_t currtime = time(NULL); | |
| 1055 cur += 2; | |
| 1056 cur[0] = '\0'; | |
| 1057 gaim_debug_info("simple","\n\nreceived - %s\n######\n%s\n#######\n\n",ctime(&currtime), conn->inbuf); | |
| 1058 msg = sipmsg_parse_header(conn->inbuf); | |
| 1059 cur[0] = '\r'; | |
| 1060 cur += 2; | |
| 1061 restlen = conn->inbufused - (cur-conn->inbuf); | |
| 1062 if(restlen>=msg->bodylen) { | |
| 1063 dummy = g_malloc(msg->bodylen+1); | |
| 1064 memcpy(dummy, cur, msg->bodylen); | |
| 1065 dummy[msg->bodylen]='\0'; | |
| 1066 msg->body = dummy; | |
| 1067 cur+=msg->bodylen; | |
| 1068 memmove(conn->inbuf, cur, conn->inbuflen); | |
| 1069 conn->inbufused=strlen(conn->inbuf); | |
| 1070 } else { | |
| 1071 sipmsg_free(msg); | |
| 1072 return; | |
| 1073 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1074 gaim_debug(GAIM_DEBUG_MISC, "simple", "in process response response: %d\n", msg->response); |
| 11189 | 1075 process_input_message(sip,msg); |
| 11181 | 1076 } else { |
| 1077 gaim_debug(GAIM_DEBUG_MISC, "simple", "received a incomplete sip msg: %s\n", conn->inbuf); | |
| 1078 } | |
| 1079 } | |
| 1080 | |
| 11189 | 1081 static void simple_udp_process(gpointer data, gint source, GaimInputCondition con) { |
| 1082 GaimConnection *gc = data; | |
| 1083 struct simple_account_data *sip = gc->proto_data; | |
| 1084 struct sipmsg *msg; | |
| 1085 int len; | |
| 1086 time_t currtime; | |
| 1087 | |
| 1088 static char buffer[65536]; | |
| 1089 len = recv(source, buffer, 65536, 0); | |
| 1090 buffer[len] = 0; | |
| 1091 gaim_debug_info("simple","\n\nreceived - %s\n######\n%s\n#######\n\n",ctime(&currtime), buffer); | |
| 1092 msg = sipmsg_parse_msg(buffer); | |
| 1093 if(msg) process_input_message(sip, msg); | |
| 1094 } | |
| 1095 | |
| 11181 | 1096 static void simple_input_cb(gpointer data, gint source, GaimInputCondition cond) |
| 1097 { | |
| 1098 GaimConnection *gc = data; | |
| 1099 struct simple_account_data *sip = gc->proto_data; | |
| 1100 int len; | |
| 1101 struct sip_connection *conn = connection_find(sip, source); | |
| 1102 if(!conn) { | |
| 1103 gaim_debug_error("simple", "Connection not found!\n"); | |
| 1104 return; | |
| 1105 } | |
| 1106 | |
| 1107 if (conn->inbuflen < conn->inbufused + SIMPLE_BUF_INC) { | |
| 1108 conn->inbuflen += SIMPLE_BUF_INC; | |
| 1109 conn->inbuf = g_realloc(conn->inbuf, conn->inbuflen); | |
| 1110 } | |
| 1111 | |
| 1112 if ((len = read(source, conn->inbuf + conn->inbufused, SIMPLE_BUF_INC - 1)) <= 0) { | |
| 1113 gaim_debug_info("simple","simple_input_cb: read error\n"); | |
| 1114 connection_remove(sip, source); | |
| 1115 if(sip->fd == source) sip->fd = -1; | |
| 1116 return; | |
| 1117 } | |
| 1118 if(len == 0) { | |
| 11341 | 1119 /* connection was closed */ |
| 11181 | 1120 connection_remove(sip, source); |
| 1121 if(sip->fd == source) sip->fd = -1; | |
| 1122 } | |
| 1123 | |
| 1124 conn->inbufused += len; | |
| 1125 conn->inbuf[conn->inbufused]='\0'; | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1126 |
| 11181 | 1127 process_input(sip, conn); |
| 1128 } | |
| 1129 | |
| 1130 /* Callback for new connections on incoming TCP port */ | |
| 1131 static void simple_newconn_cb(gpointer data, gint source, GaimInputCondition cond) { | |
| 1132 GaimConnection *gc = data; | |
| 1133 struct simple_account_data *sip = gc->proto_data; | |
| 1134 struct sip_connection *conn; | |
| 1135 | |
| 1136 int newfd = accept(source, NULL, NULL); | |
| 1137 | |
| 1138 conn = connection_create(sip, newfd); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1139 |
| 11181 | 1140 conn->inputhandler = gaim_input_add(newfd, GAIM_INPUT_READ, simple_input_cb, gc); |
| 1141 } | |
| 1142 | |
| 1143 static void login_cb(gpointer data, gint source, GaimInputCondition cond) { | |
| 1144 GaimConnection *gc = data; | |
| 1145 struct simple_account_data *sip = gc->proto_data; | |
| 1146 struct sip_connection *conn; | |
| 1147 | |
| 1148 if( source < 0 ) { | |
| 1149 gaim_connection_error(gc,"Could not connect"); | |
| 1150 return; | |
| 1151 } | |
| 1152 | |
| 1153 sip->fd = source; | |
| 1154 | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1155 conn = connection_create(sip, source); |
| 11181 | 1156 |
| 11341 | 1157 /* get the local ip */ |
| 11181 | 1158 sip->ip = g_strdup(gaim_network_get_my_ip(source)); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1159 |
| 11194 | 1160 do_register(sip); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1161 |
| 11181 | 1162 conn->inputhandler = gaim_input_add(sip->fd, GAIM_INPUT_READ, simple_input_cb, gc); |
| 1163 } | |
| 1164 | |
| 1165 static guint simple_ht_hash_nick(const char *nick) { | |
| 1166 char *lc = g_utf8_strdown(nick, -1); | |
| 1167 guint bucket = g_str_hash(lc); | |
| 1168 g_free(lc); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1169 |
| 11181 | 1170 return bucket; |
| 1171 } | |
| 1172 | |
| 1173 static gboolean simple_ht_equals_nick(const char *nick1, const char *nick2) { | |
| 1174 return (gaim_utf8_strcasecmp(nick1, nick2) == 0); | |
| 1175 } | |
| 1176 | |
| 11383 | 1177 static void srvresolved(struct srv_response *resp, int results, gpointer data) { |
| 1178 struct simple_account_data *sip = (struct simple_account_data*) data; | |
| 1179 | |
| 1180 gchar *hostname; | |
| 1181 int port = 5060; | |
| 1182 | |
| 1183 int error = 0; | |
| 1184 struct sockaddr_in addr; | |
| 1185 struct hostent *h; | |
| 1186 | |
| 1187 /* find the host to connect to */ | |
| 1188 if(results) { | |
| 1189 hostname = g_strdup(resp->hostname); | |
| 1190 port = resp->port; | |
| 1191 g_free(resp); | |
| 1192 } else { | |
| 1193 if(!gaim_account_get_bool(sip->account, "useproxy", FALSE)) { | |
| 1194 hostname = g_strdup(sip->servername); | |
| 1195 } else { | |
| 1196 hostname = g_strdup(gaim_account_get_string(sip->account, "proxy", sip->servername)); | |
| 1197 } | |
| 1198 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1199 |
| 11383 | 1200 sip->realhostname = hostname; |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1201 sip->realport = port; |
| 11383 | 1202 /* TCP case */ |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1203 if(! sip->udp) { |
| 11409 | 1204 /* create socket for incoming connections */ |
| 1205 sip->listenfd = gaim_network_listen_range(5060, 5160); | |
| 1206 if(sip->listenfd == -1) { | |
| 1207 gaim_connection_error(sip->gc, _("Could not create listen socket")); | |
| 1208 return; | |
| 1209 } | |
| 1210 gaim_debug_info("simple", "listenfd: %d\n", sip->listenfd); | |
| 1211 sip->listenport = gaim_network_get_port_from_fd(sip->listenfd); | |
| 1212 sip->listenpa = gaim_input_add(sip->listenfd, GAIM_INPUT_READ, simple_newconn_cb, sip->gc); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1213 gaim_debug_info("simple","connecting to %s port %d\n", hostname, port); |
| 11383 | 1214 /* open tcp connection to the server */ |
| 1215 error = gaim_proxy_connect(sip->account, hostname, port, login_cb, sip->gc); | |
| 1216 if(error) { | |
| 1217 gaim_connection_error(sip->gc, _("Couldn't create socket")); | |
| 1218 } | |
| 1219 | |
| 1220 } else { /* UDP */ | |
| 1221 gaim_debug_info("simple", "using udp with server %s and port %d\n", hostname, port); | |
| 1222 sip->fd = socket(AF_INET, SOCK_DGRAM, 0); | |
| 1223 | |
| 1224 addr.sin_family = AF_INET; | |
| 1225 addr.sin_port = htons(5060); | |
| 1226 addr.sin_addr.s_addr = INADDR_ANY; | |
| 1227 while((bind(sip->fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) <0) && ntohs(addr.sin_port)<5160) { | |
| 1228 addr.sin_port = htons(ntohs(addr.sin_port)+1); | |
| 1229 } | |
| 1230 sip->listenport = ntohs(addr.sin_port); | |
| 1231 sip->listenfd = sip->fd; | |
| 1232 | |
| 1233 gaim_input_add(sip->fd, GAIM_INPUT_READ, simple_udp_process, sip->gc); | |
| 1234 sip->serveraddr.sin_family = AF_INET; | |
| 1235 sip->serveraddr.sin_port = htons(port); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1236 |
| 11383 | 1237 h = gethostbyname(hostname); |
| 1238 sip->serveraddr.sin_addr.s_addr = ((struct in_addr*)h->h_addr)->s_addr; | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1239 sip->ip = g_strdup(gaim_network_get_my_ip(sip->listenfd)); |
| 11383 | 1240 sip->resendtimeout = gaim_timeout_add(2500, (GSourceFunc)resend_timeout, sip); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1241 do_register(sip); |
| 11383 | 1242 } |
| 1243 } | |
| 1244 | |
| 11181 | 1245 static void simple_login(GaimAccount *account, GaimStatus *status) |
| 1246 { | |
| 1247 GaimConnection *gc; | |
| 1248 struct simple_account_data *sip; | |
| 1249 gchar **userserver; | |
| 11210 | 1250 gchar *hosttoconnect; |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1251 |
| 11181 | 1252 const char *username = gaim_account_get_username(account); |
| 1253 | |
| 1254 gc = gaim_account_get_connection(account); | |
| 1255 gc->proto_data = sip = g_new0(struct simple_account_data,1); | |
| 1256 sip->gc=gc; | |
| 11189 | 1257 sip->account = account; |
| 11194 | 1258 sip->registerexpire = 900; |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1259 sip->udp = gaim_account_get_bool(account, "udp", FALSE); |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1260 if (strpbrk(username, " \t\v\r\n") != NULL) { |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1261 gaim_connection_error(gc, _("SIP usernames may not contain whitespaces or @ symbols")); |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1262 return; |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1263 } |
| 11181 | 1264 |
| 1265 userserver = g_strsplit(username, "@", 2); | |
| 1266 gaim_connection_set_display_name(gc,userserver[0]); | |
| 1267 sip->username = g_strdup(userserver[0]); | |
| 1268 sip->servername = g_strdup(userserver[1]); | |
| 1269 sip->password = g_strdup(gaim_connection_get_password(gc)); | |
| 1270 g_strfreev(userserver); | |
| 1271 | |
| 1272 sip->buddies = g_hash_table_new((GHashFunc)simple_ht_hash_nick, (GEqualFunc)simple_ht_equals_nick); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1273 |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1274 gaim_connection_update_progress(gc, _("Connecting"), 1, 2); |
| 11181 | 1275 |
| 1276 sip->status = g_strdup("available"); | |
| 11189 | 1277 |
| 11210 | 1278 if(!gaim_account_get_bool(account, "useproxy", FALSE)) { |
| 1279 hosttoconnect = g_strdup(sip->servername); | |
| 1280 } else { | |
| 1281 hosttoconnect = g_strdup(gaim_account_get_string(account, "proxy", sip->servername)); | |
| 1282 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1283 |
| 11341 | 1284 /* TCP case */ |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1285 if(! sip->udp) { |
| 11383 | 1286 gaim_srv_resolve("sip","tcp",hosttoconnect,srvresolved, sip); |
| 11341 | 1287 } else { /* UDP */ |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1288 gaim_srv_resolve("sip","udp",hosttoconnect,srvresolved, sip); |
| 11181 | 1289 } |
| 11210 | 1290 g_free(hosttoconnect); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1291 |
| 11341 | 1292 /* register timeout callback for register / subscribe renewal */ |
| 11194 | 1293 sip->registertimeout = gaim_timeout_add((rand()%100)+10*1000, (GSourceFunc)register_timeout, sip); |
| 11181 | 1294 } |
| 1295 | |
| 1296 static void simple_close(GaimConnection *gc) | |
| 1297 { | |
| 1298 struct simple_account_data *sip = gc->proto_data; | |
| 11194 | 1299 |
| 11341 | 1300 /* unregister */ |
| 11194 | 1301 do_register_exp(sip, 0); |
| 11346 | 1302 connection_free_all(sip); |
| 11341 | 1303 if(sip) { |
| 11181 | 1304 if(sip->servername) g_free(sip->servername); |
| 1305 if(sip->username) g_free(sip->username); | |
| 1306 if(sip->password) g_free(sip->password); | |
| 1307 if(sip->registrar.nonce) g_free(sip->registrar.nonce); | |
| 11341 | 1308 if(sip->registrar.realm) g_free(sip->registrar.realm); |
| 11181 | 1309 if(sip->proxy.nonce) g_free(sip->proxy.nonce); |
| 1310 if(sip->proxy.realm) g_free(sip->proxy.realm); | |
| 1311 if(sip->sendlater) g_free(sip->sendlater); | |
| 1312 if(sip->ip) g_free(sip->ip); | |
| 11383 | 1313 if(sip->realhostname) g_free(sip->realhostname); |
| 11409 | 1314 if(sip->listenpa) gaim_input_remove(sip->listenpa); |
| 11346 | 1315 if(sip->registertimeout) gaim_timeout_remove(sip->registertimeout); |
| 11383 | 1316 sip->servername = sip->username = sip->password = sip->registrar.nonce = sip->registrar.realm = sip->proxy.nonce = sip->proxy.realm = sip->sendlater = sip->ip = sip->realhostname = NULL; |
| 11181 | 1317 } |
| 11341 | 1318 if(gc->proto_data) g_free(gc->proto_data); |
| 1319 gc->proto_data = 0; | |
| 11181 | 1320 } |
| 1321 | |
| 11345 | 1322 /* not needed since privacy is checked for every subscribe */ |
| 1323 static void dummy_add_deny(GaimConnection *gc, const char *name) { | |
| 1324 } | |
| 1325 | |
| 1326 static void dummy_permit_deny(GaimConnection *gc) { | |
| 1327 } | |
| 1328 | |
| 11181 | 1329 static GaimPluginProtocolInfo prpl_info = |
| 1330 { | |
| 1331 0, | |
| 1332 NULL, /* user_splits */ | |
| 1333 NULL, /* protocol_options */ | |
| 1334 NO_BUDDY_ICONS, /* icon_spec */ | |
| 1335 simple_list_icon, /* list_icon */ | |
| 1336 NULL, /* list_emblems */ | |
| 1337 NULL, /* status_text */ | |
| 1338 NULL, /* tooltip_text */ | |
| 1339 simple_status_types, /* away_states */ | |
| 1340 NULL, /* blist_node_menu */ | |
| 1341 NULL, /* chat_info */ | |
| 1342 NULL, /* chat_info_defaults */ | |
| 1343 simple_login, /* login */ | |
| 1344 simple_close, /* close */ | |
| 1345 simple_im_send, /* send_im */ | |
| 1346 NULL, /* set_info */ | |
| 1347 simple_typing, /* send_typing */ | |
| 1348 NULL, /* get_info */ | |
| 1349 simple_set_status, /* set_status */ | |
| 1350 NULL, /* set_idle */ | |
| 1351 NULL, /* change_passwd */ | |
| 1352 simple_add_buddy, /* add_buddy */ | |
| 1353 NULL, /* add_buddies */ | |
| 1354 simple_remove_buddy, /* remove_buddy */ | |
| 1355 NULL, /* remove_buddies */ | |
| 11345 | 1356 dummy_add_deny, /* add_permit */ |
| 1357 dummy_add_deny, /* add_deny */ | |
| 1358 dummy_add_deny, /* rem_permit */ | |
| 1359 dummy_add_deny, /* rem_deny */ | |
| 1360 dummy_permit_deny, /* set_permit_deny */ | |
| 11181 | 1361 NULL, /* join_chat */ |
| 1362 NULL, /* reject_chat */ | |
| 1363 NULL, /* get_chat_name */ | |
| 1364 NULL, /* chat_invite */ | |
| 1365 NULL, /* chat_leave */ | |
| 1366 NULL, /* chat_whisper */ | |
| 1367 NULL, /* chat_send */ | |
| 1368 simple_keep_alive, /* keepalive */ | |
| 1369 NULL, /* register_user */ | |
| 1370 NULL, /* get_cb_info */ | |
| 1371 NULL, /* get_cb_away */ | |
| 1372 NULL, /* alias_buddy */ | |
| 1373 NULL, /* group_buddy */ | |
| 1374 NULL, /* rename_group */ | |
| 1375 NULL, /* buddy_free */ | |
| 1376 NULL, /* convo_closed */ | |
| 1377 NULL, /* normalize */ | |
| 1378 NULL, /* set_buddy_icon */ | |
| 1379 NULL, /* remove_group */ | |
| 1380 NULL, /* get_cb_real_name */ | |
| 1381 NULL, /* set_chat_topic */ | |
| 1382 NULL, /* find_blist_chat */ | |
| 1383 NULL, /* roomlist_get_list */ | |
| 1384 NULL, /* roomlist_cancel */ | |
| 1385 NULL, /* roomlist_expand_category */ | |
| 1386 NULL, /* can_receive_file */ | |
| 1387 NULL /* send_file */ | |
| 1388 }; | |
| 1389 | |
| 1390 | |
| 1391 static GaimPluginInfo info = | |
| 1392 { | |
| 1393 GAIM_PLUGIN_MAGIC, | |
| 1394 GAIM_MAJOR_VERSION, | |
| 1395 GAIM_MINOR_VERSION, | |
| 1396 GAIM_PLUGIN_PROTOCOL, /**< type */ | |
| 1397 NULL, /**< ui_requirement */ | |
| 1398 0, /**< flags */ | |
| 1399 NULL, /**< dependencies */ | |
| 1400 GAIM_PRIORITY_DEFAULT, /**< priority */ | |
| 1401 | |
| 1402 "prpl-simple", /**< id */ | |
| 1403 "SIMPLE", /**< name */ | |
| 1404 VERSION, /**< version */ | |
| 1405 N_("SIP/SIMPLE Protocol Plugin"), /** summary */ | |
| 1406 N_("The SIP/SIMPLE Protocol Plugin"), /** description */ | |
| 1407 N_("Thomas Butter <butter@uni-mannheim.de>"), /**< author */ | |
| 1408 GAIM_WEBSITE, /**< homepage */ | |
| 1409 | |
| 1410 NULL, /**< load */ | |
| 1411 NULL, /**< unload */ | |
| 1412 NULL, /**< destroy */ | |
| 1413 | |
| 1414 NULL, /**< ui_info */ | |
| 1415 &prpl_info, /**< extra_info */ | |
| 1416 NULL, | |
| 1417 NULL | |
| 1418 }; | |
| 1419 | |
| 1420 static void _init_plugin(GaimPlugin *plugin) | |
| 1421 { | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1422 GaimAccountUserSplit *split; |
| 11189 | 1423 GaimAccountOption *option; |
| 11181 | 1424 |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1425 split = gaim_account_user_split_new(_("Server"), "", '@'); |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1426 prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); |
| 11181 | 1427 |
| 11345 | 1428 option = gaim_account_option_bool_new(_("Publish Status (note: everyone may watch you)"), "dopublish", TRUE); |
| 1429 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
| 1430 | |
| 11189 | 1431 option = gaim_account_option_bool_new(_("Use UDP"), "udp", FALSE); |
| 1432 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
| 11210 | 1433 option = gaim_account_option_bool_new(_("Use Proxy"), "useproxy", FALSE); |
| 1434 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
| 1435 option = gaim_account_option_string_new(_("Proxy"), "proxy", ""); | |
| 1436 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
| 11181 | 1437 } |
| 1438 | |
| 1439 GAIM_INIT_PLUGIN(simple, _init_plugin, info); |
