Mercurial > pidgin
annotate src/protocols/simple/simple.c @ 11454:201617d49573
[gaim-migrate @ 13693]
This commit includes a number of changes:
1. Aliases are now used consistently in chats. If the prpl uses unique screen names for chats (e.g. Jabber), then aliases are not used at all.
2. The chat list is now colorized to match the colors used in the chat itself.
3. Buddies are bolded in the chat user list.
4. Buddies are sorted above non-buddies in the chat user list.
5. The chat user list is ellipsized when possible (i.e. on GTK+ 2.6.0 or above).
6. I've accepted patch #1178248, by Matt Amato to add "buddy-added" and "buddy-removed" signals. These were used in my implementation of #3 and #4, to update the GUI when users are added or removed from the buddy list.
7. I've added a "blist-node-aliased" signal that is emitted when a buddy, contact, or chat is aliased.
8. Since it was hard to separate and I need it at some point, I'm letting it slip in... I've changed GaimConversation.log to be a GList named logs. This way, we can have multiple logs for a single conversation. This will be necessary to implement unnamed chat logging in some reasonable fasion (see my notes in the TODO file).
committer: Tailor Script <tailor@pidgin.im>
| author | Richard Laager <rlaager@wiktel.com> |
|---|---|
| date | Tue, 06 Sep 2005 03:04:07 +0000 |
| parents | 617e67e1c985 |
| children | 0d18fa6c3b41 |
| 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 | |
| 250 type = gaim_status_type_new(GAIM_STATUS_ONLINE, "online", _("Online"), FALSE); | |
| 251 types = g_list_append(types, type); | |
| 252 | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
253 type = gaim_status_type_new_with_attrs( |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
254 GAIM_STATUS_AVAILABLE, "available", _("Available"), |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
255 TRUE, TRUE, FALSE, |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
256 "message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), NULL); |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
257 types = g_list_append(types, type); |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
258 |
| 11181 | 259 return types; |
| 260 } | |
| 261 | |
| 11346 | 262 static gchar *auth_header(struct simple_account_data *sip, struct sip_auth *auth, gchar *method, gchar *target) { |
| 263 gchar noncecount[9]; | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
264 HASHHEX HA2; |
| 11346 | 265 HASHHEX response; |
| 266 gchar *ret; | |
| 11409 | 267 gchar *tmp; |
| 268 | |
| 269 if(auth->type == 1) { /* Digest */ | |
| 270 sprintf(noncecount, "%08d", auth->nc++); | |
| 271 DigestCalcResponse(auth->HA1, auth->nonce, noncecount, "", "", method, target, HA2, response); | |
| 272 gaim_debug(GAIM_DEBUG_MISC, "simple", "response %s\n", response); | |
| 273 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); | |
| 274 return ret; | |
| 275 } else if(auth->type == 2) { /* NTLM */ | |
| 276 if(auth->nc == 3) { | |
| 277 ret = gaim_ntlm_gen_type3(sip->username, sip->password, "gaim", sip->servername, auth->nonce); | |
| 11424 | 278 tmp = g_strdup_printf("NTLM qop=\"auth\" realm=\"%s\" targetname=\"%s\" response=\"%s\"\r\n",auth->realm, auth->target, ret); |
| 11409 | 279 g_free(ret); |
| 280 return tmp; | |
| 281 } | |
| 282 ret = gaim_ntlm_gen_type1("gaim", sip->servername); | |
| 11424 | 283 /* tmp = g_strdup_printf("NTLM qop=\"auth\" realm=\"%s\" targetname=\"%s\" response=\"%s\"\r\n", auth->realm, auth->target, ret); */ |
| 284 tmp = g_strdup_printf("NTLM qop=\"auth\" realm=\"%s\" targetname=\"%s\" response=\"010000003134303017f6dcfb4531f92f\"\r\n", auth->realm, auth->target); | |
| 11409 | 285 g_free(ret); |
| 286 return tmp; | |
| 287 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
288 |
| 11346 | 289 sprintf(noncecount, "%08d", auth->nc++); |
| 290 DigestCalcResponse(auth->HA1, auth->nonce, noncecount, "", "", method, target, HA2, response); | |
| 291 gaim_debug(GAIM_DEBUG_MISC, "simple", "response %s\n", response); | |
| 292 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); | |
| 293 return ret; | |
| 294 } | |
| 295 | |
| 296 static void fill_auth(struct simple_account_data *sip, gchar *hdr, struct sip_auth *auth) { | |
| 11409 | 297 int i=0; |
| 11424 | 298 char *tmp; |
| 299 char *tmp2; | |
|
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
300 gchar **parts; |
| 11346 | 301 if(!hdr) { |
| 11409 | 302 gaim_debug_error("simple", "fill_auth: hdr==NULL\n"); |
| 11346 | 303 return; |
| 304 } | |
| 11409 | 305 |
| 306 if(!g_strncasecmp(hdr, "NTLM", 4)) { | |
| 307 gaim_debug_info("simple", "found NTLM\n"); | |
| 308 auth->type = 2; | |
| 309 if(!auth->nonce && !auth->nc) { | |
|
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
310 parts = g_strsplit(hdr, " ", 0); |
| 11424 | 311 while(parts[i]) { |
| 312 if(!strncmp(parts[i],"targetname",10)) { | |
| 313 auth->target = g_strndup(parts[i]+12,strlen(parts[i]+12)-1); | |
| 314 } | |
| 315 if(!strncmp(parts[i],"realm",5)) { | |
| 316 tmp = strstr(hdr, "realm="); | |
| 317 tmp += 7; | |
| 318 tmp2 = strchr(tmp, '"'); | |
| 319 *tmp2 = 0; | |
| 320 auth->realm = g_strdup(tmp); | |
| 321 *tmp2 = '"'; | |
| 322 } | |
| 323 i++; | |
| 324 } | |
|
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
325 g_strfreev(parts); |
|
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
326 parts = NULL; |
| 11409 | 327 auth->nc = 1; |
| 328 } | |
| 329 if(!auth->nonce && auth->nc==2) { | |
| 330 auth->nc = 3; | |
| 331 auth->nonce = gaim_ntlm_parse_type2(hdr+5); | |
| 332 } | |
| 333 return; | |
| 334 } | |
| 335 | |
| 336 auth->type = 1; | |
|
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
337 parts = g_strsplit(hdr, " ", 0); |
| 11346 | 338 while(parts[i]) { |
| 339 if(!strncmp(parts[i],"nonce",5)) { | |
| 340 auth->nonce = g_strndup(parts[i]+7,strlen(parts[i]+7)-1); | |
| 341 } | |
| 342 if(!strncmp(parts[i],"realm",5)) { | |
| 343 auth->realm = g_strndup(parts[i]+7,strlen(parts[i]+7)-2); | |
| 344 } | |
| 345 i++; | |
| 346 } | |
|
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
347 g_strfreev(parts); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
348 |
| 11346 | 349 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
|
350 |
| 11346 | 351 DigestCalcHA1("md5", sip->username, auth->realm, sip->password, auth->nonce, "", auth->HA1); |
| 352 | |
| 353 auth->nc=1; | |
| 354 } | |
| 355 | |
| 11181 | 356 static void simple_input_cb(gpointer data, gint source, GaimInputCondition cond); |
| 357 | |
| 358 static void send_later_cb(gpointer data, gint source, GaimInputCondition cond) { | |
| 359 GaimConnection *gc = data; | |
| 360 struct simple_account_data *sip = gc->proto_data; | |
| 361 struct sip_connection *conn; | |
| 362 | |
| 363 if( source < 0 ) { | |
| 364 gaim_connection_error(gc,"Could not connect"); | |
| 365 return; | |
| 366 } | |
| 367 | |
| 368 sip->fd = source; | |
| 369 sip->connecting = 0; | |
| 370 write(sip->fd, sip->sendlater, strlen(sip->sendlater)); | |
| 371 conn = connection_create(sip, source); | |
| 372 conn->inputhandler = gaim_input_add(sip->fd, GAIM_INPUT_READ, simple_input_cb, gc); | |
| 373 g_free(sip->sendlater); | |
| 374 sip->sendlater = 0; | |
| 375 } | |
| 376 | |
| 377 | |
| 378 static void sendlater(GaimConnection *gc, const char *buf) { | |
| 379 struct simple_account_data *sip = gc->proto_data; | |
| 380 int error = 0; | |
| 381 if(!sip->connecting) { | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
382 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
|
383 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
|
384 if(error) { |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
385 gaim_connection_error(gc, _("Couldn't create socket")); |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
386 } |
| 11181 | 387 sip->connecting = 1; |
| 388 } | |
| 389 if(sip->sendlater) { | |
| 390 gchar *old = sip->sendlater; | |
| 391 sip->sendlater = g_strdup_printf("%s\r\n%s",old, buf); | |
| 392 } else { | |
| 393 sip->sendlater = g_strdup(buf); | |
| 394 } | |
| 395 } | |
| 396 | |
| 397 static int sendout_pkt(GaimConnection *gc, const char *buf) { | |
| 398 struct simple_account_data *sip = gc->proto_data; | |
| 399 time_t currtime = time(NULL); | |
| 11189 | 400 int ret = 0; |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
401 |
| 11181 | 402 gaim_debug(GAIM_DEBUG_MISC, "simple", "\n\nsending - %s\n######\n%s\n######\n\n", ctime(&currtime), buf); |
| 11189 | 403 if(sip->udp) { |
| 404 if(sendto(sip->fd, buf, strlen(buf), 0, (struct sockaddr*)&sip->serveraddr, sizeof(struct sockaddr_in)) < strlen(buf)) { | |
| 405 gaim_debug_info("simple", "could not send packet\n"); | |
| 406 } | |
| 407 } else { | |
| 408 if(sip->fd <0 ) { | |
| 409 sendlater(gc, buf); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
410 return 0; |
| 11189 | 411 } |
| 412 ret = write(sip->fd, buf, strlen(buf)); | |
| 413 if(ret < 0) { | |
| 414 sendlater(gc,buf); | |
| 415 return 0; | |
| 416 } | |
| 11181 | 417 } |
| 418 return ret; | |
| 419 } | |
| 420 | |
| 11194 | 421 static void sendout_sipmsg(struct simple_account_data *sip, struct sipmsg *msg) { |
| 422 gchar *oldstr; | |
| 423 gchar *outstr = g_strdup_printf("%s %s SIP/2.0\r\n", msg->method, msg->target); | |
| 424 gchar *name; | |
| 425 gchar *value; | |
| 426 GSList *tmp = msg->headers; | |
| 427 while(tmp) { | |
| 428 oldstr = outstr; | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
429 name = ((struct siphdrelement*)(tmp->data))->name; |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
430 value = ((struct siphdrelement*)(tmp->data))->value; |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
431 outstr = g_strdup_printf("%s%s: %s\r\n",oldstr, name, value); |
| 11194 | 432 g_free(oldstr); |
| 433 tmp = g_slist_next(tmp); | |
| 434 } | |
| 435 oldstr = outstr; | |
| 436 if(msg->body) outstr = g_strdup_printf("%s\r\n%s", outstr, msg->body); | |
| 437 else outstr = g_strdup_printf("%s\r\n", outstr); | |
| 438 g_free(oldstr); | |
| 439 sendout_pkt(sip->gc, outstr); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
440 g_free(outstr); |
| 11194 | 441 } |
| 442 | |
| 11181 | 443 static void send_sip_response(GaimConnection *gc, struct sipmsg *msg, int code, char *text, char *body) { |
| 444 GSList *tmp = msg->headers; | |
| 445 char *oldstr; | |
| 446 char *name; | |
| 447 char *value; | |
| 448 char *outstr = g_strdup_printf("SIP/2.0 %d %s\r\n",code, text); | |
| 449 while(tmp) { | |
| 450 oldstr = outstr; | |
| 451 name = ((struct siphdrelement*)(tmp->data))->name; | |
| 452 value = ((struct siphdrelement*)(tmp->data))->value; | |
| 453 outstr = g_strdup_printf("%s%s: %s\r\n",oldstr, name, value); | |
| 454 g_free(oldstr); | |
| 455 tmp = g_slist_next(tmp); | |
| 456 } | |
| 457 oldstr = outstr; | |
| 458 if(body) outstr = g_strdup_printf("%s\r\n%s",outstr,body); | |
| 459 else outstr = g_strdup_printf("%s\r\n",outstr); | |
| 460 g_free(oldstr); | |
| 461 sendout_pkt(gc, outstr); | |
| 462 g_free(outstr); | |
| 463 } | |
| 464 | |
| 11194 | 465 static void transactions_remove(struct simple_account_data *sip, struct transaction *trans) { |
| 466 if(trans->msg) sipmsg_free(trans->msg); | |
| 467 sip->transactions = g_slist_remove(sip->transactions, trans); | |
| 468 g_free(trans); | |
| 469 } | |
| 470 | |
| 11181 | 471 static void transactions_add_buf(struct simple_account_data *sip, gchar *buf, void *callback) { |
| 472 struct transaction *trans = g_new0(struct transaction, 1); | |
| 473 trans->time = time(NULL); | |
| 474 trans->msg = sipmsg_parse_msg(buf); | |
| 475 trans->cseq = sipmsg_find_header(trans->msg, "CSeq"); | |
| 476 trans->callback = callback; | |
| 477 sip->transactions = g_slist_append(sip->transactions, trans); | |
| 478 } | |
| 479 | |
| 480 static struct transaction *transactions_find(struct simple_account_data *sip, struct sipmsg *msg) { | |
| 481 struct transaction *trans; | |
| 482 GSList *transactions = sip->transactions; | |
| 483 gchar *cseq = sipmsg_find_header(msg, "CSeq"); | |
| 484 | |
| 485 while(transactions) { | |
| 486 trans = transactions->data; | |
| 487 if(!strcmp(trans->cseq, cseq)) { | |
| 488 return trans; | |
| 489 } | |
| 490 transactions = transactions->next; | |
| 491 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
492 |
| 11181 | 493 return (struct transaction *)NULL; |
| 494 } | |
| 495 | |
| 496 static void send_sip_request(GaimConnection *gc, gchar *method, gchar *url, gchar *to, gchar *addheaders, gchar *body, struct sip_dialog *dialog, TransCallback tc) { | |
| 497 struct simple_account_data *sip = gc->proto_data; | |
| 498 char *callid= dialog ? g_strdup(dialog->callid) : gencallid(); | |
| 499 char *auth=""; | |
| 500 char *addh=""; | |
| 501 gchar *branch = genbranch(); | |
| 502 char *buf; | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
503 |
| 11181 | 504 if(addheaders) addh=addheaders; |
| 11409 | 505 if(sip->registrar.type && !strcmp(method,"REGISTER")) { |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
506 buf = auth_header(sip, &sip->registrar, method, url); |
| 11346 | 507 auth = g_strdup_printf("Authorization: %s",buf); |
| 508 g_free(buf); | |
| 11181 | 509 gaim_debug(GAIM_DEBUG_MISC, "simple", "header %s", auth); |
| 510 } | |
| 511 | |
| 11409 | 512 if(sip->proxy.type && strcmp(method,"REGISTER")) { |
| 11346 | 513 buf = auth_header(sip, &sip->proxy, method, url); |
| 514 auth = g_strdup_printf("Proxy-Authorization: %s",buf); | |
| 515 g_free(buf); | |
| 11181 | 516 gaim_debug(GAIM_DEBUG_MISC, "simple", "header %s", auth); |
| 517 } | |
| 518 | |
| 519 buf = g_strdup_printf("%s %s SIP/2.0\r\n" | |
| 11190 | 520 "Via: SIP/2.0/%s %s:%d;branch=%s\r\n" |
| 11181 | 521 "From: <sip:%s@%s>;tag=%s\r\n" |
| 522 "To: <%s>%s%s\r\n" | |
| 523 "Max-Forwards: 10\r\n" | |
| 524 "CSeq: %d %s\r\n" | |
| 525 "User-Agent: Gaim SIP/SIMPLE Plugin\r\n" | |
| 526 "Call-ID: %s\r\n" | |
| 527 "%s%s" | |
| 528 "Content-Length: %d\r\n\r\n%s", | |
| 529 method, | |
| 530 url, | |
| 11190 | 531 sip->udp ? "UDP" : "TCP", |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
532 sip->ip ? sip->ip : "", |
| 11181 | 533 sip->listenport, |
| 534 branch, | |
| 535 sip->username, | |
| 536 sip->servername, | |
| 537 dialog ? dialog->ourtag : gentag(), | |
| 538 to, | |
| 539 dialog ? ";tag=" : "", | |
| 540 dialog ? dialog->theirtag : "", | |
| 541 ++sip->cseq, | |
| 542 method, | |
| 543 callid, | |
| 544 auth, | |
| 545 addh, | |
| 546 strlen(body), | |
| 547 body); | |
| 548 g_free(branch); | |
| 549 g_free(callid); | |
| 550 | |
| 11341 | 551 /* add to ongoing transactions */ |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
552 |
| 11181 | 553 transactions_add_buf(sip, buf, tc); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
554 |
| 11181 | 555 sendout_pkt(gc,buf); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
556 |
| 11181 | 557 g_free(buf); |
| 558 } | |
| 559 | |
| 11194 | 560 static void do_register_exp(struct simple_account_data *sip, int expire) { |
| 11181 | 561 char *uri = g_strdup_printf("sip:%s",sip->servername); |
| 562 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
|
563 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
|
564 |
|
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
565 sip->registerstatus = 1; |
|
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
566 |
| 11194 | 567 if(expire) { |
| 568 sip->reregister = time(NULL) + expire - 50; | |
| 569 } else { | |
| 570 sip->reregister = time(NULL) + 600; | |
| 571 } | |
| 572 send_sip_request(sip->gc,"REGISTER",uri,to, contact, "", NULL, process_register_response); | |
| 11341 | 573 g_free(contact); |
| 11181 | 574 g_free(uri); |
| 575 g_free(to); | |
| 576 } | |
| 577 | |
| 11194 | 578 static void do_register(struct simple_account_data *sip) { |
| 579 do_register_exp(sip, sip->registerexpire); | |
| 580 } | |
| 581 | |
| 11181 | 582 static gchar *parse_from(gchar *hdr) { |
| 583 gchar *from = hdr; | |
| 584 gchar *tmp; | |
| 585 | |
| 586 if(!from) return NULL; | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
587 gaim_debug_info("simple", "parsing address out of %s\n",from); |
| 11181 | 588 tmp = strchr(from, '<'); |
| 589 | |
| 11341 | 590 /* i hate the different SIP UA behaviours... */ |
| 591 if(tmp) { /* sip address in <...> */ | |
| 11181 | 592 from = tmp+1; |
| 593 tmp = strchr(from,'>'); | |
| 594 if(tmp) { | |
| 595 from = g_strndup(from,tmp-from); | |
| 596 } else { | |
| 597 gaim_debug_info("simple", "found < without > in From\n"); | |
| 598 return NULL; | |
| 599 } | |
| 600 } else { | |
| 601 tmp = strchr(from, ';'); | |
| 602 if(tmp) { | |
| 603 from = g_strndup(from,tmp-from); | |
| 604 } | |
| 605 } | |
| 606 gaim_debug_info("simple", "got %s\n",from); | |
| 607 return from; | |
| 608 } | |
| 609 | |
| 610 static gboolean process_subscribe_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { | |
| 11341 | 611 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
|
612 |
| 11181 | 613 if(msg->response==200 || msg->response==202) { |
| 614 return TRUE; | |
| 615 } | |
| 616 | |
| 11341 | 617 /* 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
|
618 |
| 11181 | 619 gaim_prpl_got_user_status(sip->account, to, "offline", NULL); |
| 620 g_free(to); | |
| 621 return TRUE; | |
| 622 } | |
| 623 | |
| 624 static void simple_subscribe(struct simple_account_data *sip, struct simple_buddy *buddy) { | |
| 11341 | 625 gchar *contact = "Expires: 300\r\nAccept: application/pidf+xml\r\nEvent: presence\r\n"; |
| 11181 | 626 gchar *to; |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
627 if(strstr(buddy->name,"sip:")) to = g_strdup(buddy->name); |
| 11181 | 628 else to = g_strdup_printf("sip:%s",buddy->name); |
| 11341 | 629 contact = g_strdup_printf("%sContact: <%s@%s>\r\n", contact, sip->username, sip->servername); |
| 630 /* subscribe to buddy presence | |
| 631 * 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
|
632 |
| 11181 | 633 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
|
634 |
| 11181 | 635 g_free(to); |
| 11341 | 636 g_free(contact); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
637 |
| 11341 | 638 /* resubscribe before subscription expires */ |
| 639 /* add some jitter */ | |
| 640 buddy->resubscribe = time(NULL)+250+(rand()%50); | |
| 11181 | 641 } |
| 642 | |
| 643 static void simple_buddy_resub(char *name, struct simple_buddy *buddy, struct simple_account_data *sip) { | |
| 644 time_t curtime = time(NULL); | |
| 11341 | 645 gaim_debug_info("simple","buddy resub\n"); |
| 11181 | 646 if(buddy->resubscribe < curtime) { |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
647 gaim_debug(GAIM_DEBUG_MISC, "simple", "simple_buddy_resub %s\n",name); |
| 11181 | 648 simple_subscribe(sip, buddy); |
| 649 } | |
| 650 } | |
| 651 | |
| 11194 | 652 static gboolean resend_timeout(struct simple_account_data *sip) { |
| 653 GSList *tmp = sip->transactions; | |
| 654 time_t currtime = time(NULL); | |
| 655 while(tmp) { | |
| 656 struct transaction *trans = tmp->data; | |
| 657 tmp = tmp->next; | |
| 658 gaim_debug_info("simple", "have open transaction age: %d\n", currtime- trans->time); | |
| 659 if((currtime - trans->time > 5) && trans->retries >= 1) { | |
| 11341 | 660 /* TODO 408 */ |
| 11194 | 661 } else { |
| 662 if((currtime - trans->time > 2) && trans->retries == 0) { | |
| 663 trans->retries++; | |
| 664 sendout_sipmsg(sip, trans->msg); | |
| 665 } | |
| 666 } | |
| 667 } | |
| 668 return TRUE; | |
| 669 } | |
| 670 | |
| 11181 | 671 static gboolean register_timeout(struct simple_account_data *sip) { |
| 672 GSList *tmp; | |
| 673 time_t curtime = time(NULL); | |
| 11341 | 674 /* register again if first registration expires */ |
| 11181 | 675 if(sip->reregister < curtime) { |
| 11194 | 676 do_register(sip); |
| 11181 | 677 } |
| 11341 | 678 gaim_debug_info("simple","in register timeout\n"); |
| 679 /* check for every subscription if we need to resubscribe */ | |
| 11181 | 680 g_hash_table_foreach(sip->buddies, (GHFunc)simple_buddy_resub, (gpointer)sip); |
| 681 | |
| 11341 | 682 /* remove a timed out suscriber */ |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
683 |
| 11181 | 684 tmp = sip->watcher; |
| 685 while(tmp) { | |
| 686 struct simple_watcher *watcher = tmp->data; | |
| 687 if(watcher->expire < curtime) { | |
| 688 watcher_remove(sip, watcher->name); | |
| 689 tmp = sip->watcher; | |
| 690 } | |
| 691 if(tmp) tmp = tmp->next; | |
| 692 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
693 |
| 11181 | 694 return TRUE; |
| 695 } | |
| 696 | |
| 697 static void simple_send_message(struct simple_account_data *sip, char *to, char *msg, char *type) { | |
| 698 gchar *hdr; | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
699 if(type) { |
| 11181 | 700 hdr = g_strdup_printf("Content-Type: %s\r\n",type); |
| 701 } else { | |
| 702 hdr = g_strdup("Content-Type: text/plain\r\n"); | |
| 703 } | |
| 704 send_sip_request(sip->gc, "MESSAGE", to, to, hdr, msg, NULL, NULL); | |
| 705 g_free(hdr); | |
| 706 } | |
| 707 | |
| 708 static int simple_im_send(GaimConnection *gc, const char *who, const char *what, GaimConvImFlags flags) { | |
| 709 struct simple_account_data *sip = gc->proto_data; | |
| 710 char *to = g_strdup(who); | |
| 711 char *text = g_strdup(what); | |
| 712 simple_send_message(sip, to, text, NULL); | |
| 713 g_free(to); | |
| 714 g_free(text); | |
| 715 return 1; | |
| 716 } | |
| 717 | |
| 718 static void process_incoming_message(struct simple_account_data *sip, struct sipmsg *msg) { | |
| 719 gchar *from; | |
| 720 gchar *contenttype; | |
| 721 gboolean found = FALSE; | |
| 722 | |
| 723 from = parse_from(sipmsg_find_header(msg, "From")); | |
| 724 | |
| 725 if(!from) return; | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
726 |
| 11181 | 727 gaim_debug(GAIM_DEBUG_MISC, "simple", "got message from %s: %s\n", from, msg->body); |
| 728 | |
| 729 contenttype = sipmsg_find_header(msg, "Content-Type"); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
730 if(!contenttype || !strncmp(contenttype, "text/plain", 10) || !strncmp(contenttype, "text/html", 9)) { |
| 11181 | 731 serv_got_im(sip->gc, from, msg->body, 0, time(NULL)); |
| 732 send_sip_response(sip->gc, msg, 200, "OK", NULL); | |
| 733 found = TRUE; | |
| 734 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
735 if(!strncmp(contenttype, "application/im-iscomposing+xml",30)) { |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
736 xmlnode *isc = xmlnode_from_str(msg->body, msg->bodylen); |
| 11181 | 737 xmlnode *state; |
| 738 gchar *statedata; | |
| 739 | |
| 740 if(!isc) { | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
741 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
|
742 return; |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
743 } |
| 11181 | 744 |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
745 state = xmlnode_get_child(isc, "state"); |
| 11181 | 746 |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
747 if(!state) { |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
748 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
|
749 return; |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
750 } |
| 11181 | 751 |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
752 statedata = xmlnode_get_data(state); |
| 11181 | 753 if(statedata) { |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
754 if(strstr(statedata,"active")) serv_got_typing(sip->gc, from, 0, GAIM_TYPING); |
| 11181 | 755 else serv_got_typing_stopped(sip->gc, from); |
| 756 } | |
| 757 xmlnode_free(isc); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
758 send_sip_response(sip->gc, msg, 200, "OK", NULL); |
| 11181 | 759 found = TRUE; |
| 760 } | |
| 761 if(!found) { | |
| 762 gaim_debug_info("simple", "got unknown mime-type"); | |
| 763 send_sip_response(sip->gc, msg, 415, "Unsupported media type", NULL); | |
| 764 } | |
| 765 g_free(from); | |
| 766 } | |
| 767 | |
| 768 | |
| 769 gboolean process_register_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { | |
| 770 gchar *tmp; | |
| 771 gaim_debug(GAIM_DEBUG_MISC, "simple", "in process register response response: %d\n", msg->response); | |
| 772 switch (msg->response) { | |
| 773 case 200: | |
| 11341 | 774 if(sip->registerstatus<3) { /* registered */ |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
775 if(gaim_account_get_bool(sip->account, "dopublish", TRUE)) { |
| 11345 | 776 send_publish(sip); |
| 777 } | |
| 11181 | 778 } |
| 779 sip->registerstatus=3; | |
| 780 gaim_connection_set_state(sip->gc, GAIM_CONNECTED); | |
| 11341 | 781 |
| 782 /* get buddies from blist */ | |
| 783 simple_get_buddies(sip->gc); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
784 |
| 11181 | 785 register_timeout(sip); |
| 786 break; | |
| 787 case 401: | |
| 788 if(sip->registerstatus!=2) { | |
| 11346 | 789 gaim_debug_info("simple","REGISTER retries %d\n",sip->registrar.retries); |
| 790 if(sip->registrar.retries>3) { | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
791 gaim_connection_error(sip->gc,"Wrong Password"); |
| 11346 | 792 return TRUE; |
| 793 } | |
| 11181 | 794 tmp = sipmsg_find_header(msg, "WWW-Authenticate"); |
| 795 fill_auth(sip, tmp, &sip->registrar); | |
| 796 sip->registerstatus=2; | |
| 11194 | 797 do_register(sip); |
| 11181 | 798 } |
| 799 break; | |
| 800 } | |
| 801 return TRUE; | |
| 802 } | |
| 803 | |
| 804 static void process_incoming_notify(struct simple_account_data *sip, struct sipmsg *msg) { | |
| 805 gchar *from; | |
| 806 gchar *fromhdr; | |
| 807 gchar *tmp2; | |
| 808 xmlnode *pidf; | |
| 809 xmlnode *basicstatus; | |
| 810 gboolean isonline = FALSE; | |
| 811 | |
| 812 fromhdr = sipmsg_find_header(msg,"From"); | |
| 813 from = parse_from(fromhdr); | |
| 814 if(!from) return; | |
| 815 | |
| 816 pidf = xmlnode_from_str(msg->body, msg->bodylen); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
817 |
| 11181 | 818 if(!pidf) { |
| 819 gaim_debug_info("simple","process_incoming_notify: no parseable pidf\n"); | |
| 820 return; | |
| 821 } | |
| 822 | |
| 823 basicstatus = xmlnode_get_child(xmlnode_get_child(xmlnode_get_child(pidf,"tuple"),"status"), "basic"); | |
| 824 | |
| 825 if(!basicstatus) { | |
| 826 gaim_debug_info("simple","process_incoming_notify: no basic found\n"); | |
| 827 return; | |
| 828 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
829 |
| 11181 | 830 tmp2 = xmlnode_get_data(basicstatus); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
831 |
| 11181 | 832 if(!tmp2) { |
| 833 gaim_debug_info("simple","process_incoming_notify: no basic data found\n"); | |
| 834 return; | |
| 835 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
836 |
| 11181 | 837 if(strstr(tmp2, "open")) { |
| 838 isonline = TRUE; | |
| 839 } | |
| 840 | |
| 841 if(isonline) gaim_prpl_got_user_status(sip->account, from, "available", NULL); | |
| 842 else gaim_prpl_got_user_status(sip->account, from, "offline", NULL); | |
| 843 | |
| 844 xmlnode_free(pidf); | |
| 845 | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
846 g_free(from); |
| 11181 | 847 send_sip_response(sip->gc, msg, 200, "OK", NULL); |
| 848 } | |
| 849 | |
| 850 static int simple_typing(GaimConnection *gc, const char *name, int typing) { | |
| 851 struct simple_account_data *sip = gc->proto_data; | |
| 852 | |
| 853 gchar *xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" | |
| 854 "<isComposing xmlns=\"urn:ietf:params:xml:ns:im-iscomposing\"\n" | |
| 855 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" | |
| 856 "xsi:schemaLocation=\"urn:ietf:params:xml:ns:im-composing iscomposing.xsd\">\n" | |
| 857 "<state>%s</state>\n" | |
| 858 "<contenttype>text/plain</contenttype>\n" | |
| 859 "<refresh>60</refresh>\n" | |
| 860 "</isComposing>"; | |
| 861 gchar *recv = g_strdup(name); | |
| 862 if(typing == GAIM_TYPING) { | |
| 863 gchar *msg = g_strdup_printf(xml, "active"); | |
| 864 simple_send_message(sip, recv, msg, "application/im-iscomposing+xml"); | |
| 865 g_free(msg); | |
| 866 } else { | |
| 867 gchar *msg = g_strdup_printf(xml, "idle"); | |
| 868 simple_send_message(sip, recv, msg, "application/im-iscomposing+xml"); | |
| 869 g_free(msg); | |
| 870 } | |
| 871 g_free(recv); | |
| 872 return 1; | |
| 873 } | |
| 874 | |
| 875 static gchar *find_tag(gchar *hdr) { | |
| 876 gchar *tmp = strstr(hdr, ";tag="); | |
| 877 gchar *tmp2; | |
| 878 if(!tmp) return NULL; | |
| 879 tmp += 5; | |
| 880 if((tmp2 = strchr(tmp, ';'))) { | |
| 881 tmp2[0] = '\0'; | |
| 882 tmp = g_strdup(tmp); | |
| 883 tmp2[0] = ';'; | |
| 884 return tmp; | |
| 885 } | |
| 886 return g_strdup(tmp); | |
| 887 } | |
| 888 | |
| 889 static gchar* gen_pidf(struct simple_account_data *sip) { | |
| 890 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
|
891 "<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n" |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
892 "xmlns:im=\"urn:ietf:params:xml:ns:pidf:im\"\n" |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
893 "entity=\"sip:%s@%s\">\n" |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
894 "<tuple id=\"bs35r9f\">\n" |
| 11181 | 895 "<status>\n" |
| 896 "<basic>open</basic>\n" | |
| 897 "<im:im>%s</im:im>\n" | |
| 898 "</status>\n" | |
| 899 "</tuple>\n" | |
| 900 "</presence>", | |
| 901 sip->username, | |
| 902 sip->servername, | |
| 903 sip->status); | |
| 904 return doc; | |
| 905 } | |
| 906 | |
| 907 static void send_notify(struct simple_account_data *sip, struct simple_watcher *watcher) { | |
| 908 gchar *doc = gen_pidf(sip); | |
| 909 send_sip_request(sip->gc, "NOTIFY", watcher->name, watcher->name, "Event: presence\r\nContent-Type: application/pidf+xml\r\n", doc, &watcher->dialog, NULL); | |
| 910 g_free(doc); | |
| 911 } | |
| 912 | |
| 913 static gboolean process_publish_response(struct simple_account_data *sip, struct sipmsg *msg, struct transaction *tc) { | |
| 11345 | 914 if(msg->response != 200 && msg->response != 408) { |
| 11341 | 915 /* never send again */ |
| 11181 | 916 sip->republish = -1; |
| 917 } | |
| 918 return TRUE; | |
| 919 } | |
| 920 | |
| 921 static void send_publish(struct simple_account_data *sip) { | |
| 922 gchar *uri = g_strdup_printf("sip:%s@%s", sip->username, sip->servername); | |
| 923 gchar *doc = gen_pidf(sip); | |
| 11341 | 924 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 | 925 sip->republish = time(NULL) + 500; |
| 926 g_free(doc); | |
| 927 } | |
| 928 | |
| 929 static void process_incoming_subscribe(struct simple_account_data *sip, struct sipmsg *msg) { | |
| 930 gchar *from = parse_from(sipmsg_find_header(msg, "From")); | |
| 931 gchar *theirtag = find_tag(sipmsg_find_header(msg, "From")); | |
| 932 gchar *ourtag = find_tag(sipmsg_find_header(msg, "To")); | |
| 933 gboolean tagadded = FALSE; | |
| 934 gchar *callid = sipmsg_find_header(msg, "Call-ID"); | |
| 935 gchar *expire = sipmsg_find_header(msg, "Expire"); | |
| 936 gchar *tmp; | |
| 937 struct simple_watcher *watcher = watcher_find(sip, from); | |
| 938 if(!ourtag) { | |
| 939 tagadded = TRUE; | |
| 940 ourtag = gentag(); | |
| 941 } | |
| 11341 | 942 if(!watcher) { /* new subscription */ |
| 11345 | 943 if(!gaim_privacy_check(sip->account, from)) { |
| 944 send_sip_response(sip->gc, msg, 202, "Ok", NULL); | |
| 945 goto privend; | |
| 946 } | |
| 11181 | 947 watcher = watcher_create(sip, from, callid, ourtag, theirtag); |
| 948 } | |
| 949 if(tagadded) { | |
| 950 gchar *to = g_strdup_printf("%s;tag=%s", sipmsg_find_header(msg, "To"), ourtag); | |
| 951 sipmsg_remove_header(msg, "To"); | |
| 952 sipmsg_add_header(msg, "To", to); | |
| 953 } | |
| 954 if(expire) | |
| 955 watcher->expire = time(NULL) + strtol(expire, NULL, 10); | |
| 956 else | |
| 957 watcher->expire = time(NULL) + 600; | |
| 958 sipmsg_remove_header(msg, "Contact"); | |
| 959 tmp = g_strdup_printf("<%s@%s>",sip->username, sip->servername); | |
| 960 sipmsg_add_header(msg, "Contact", tmp); | |
| 961 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); | |
| 962 send_sip_response(sip->gc, msg, 200, "Ok", NULL); | |
| 963 g_free(tmp); | |
| 964 send_notify(sip, watcher); | |
| 11345 | 965 privend: |
| 966 g_free(from); | |
| 967 g_free(theirtag); | |
| 968 g_free(ourtag); | |
| 969 g_free(callid); | |
| 970 g_free(expire); | |
| 11181 | 971 } |
| 972 | |
| 11189 | 973 static void process_input_message(struct simple_account_data *sip, struct sipmsg *msg) { |
| 974 int found = 0; | |
| 11341 | 975 if( msg->response == 0 ) { /* request */ |
| 11189 | 976 if(!strcmp(msg->method, "MESSAGE")) { |
| 977 process_incoming_message(sip, msg); | |
| 978 found = 1; | |
| 979 } | |
| 980 if(!strcmp(msg->method, "NOTIFY")) { | |
| 981 process_incoming_notify(sip, msg); | |
| 982 found = 1; | |
| 983 } | |
| 984 if(!strcmp(msg->method, "SUBSCRIBE")) { | |
| 985 process_incoming_subscribe(sip, msg); | |
| 986 found = 1; | |
| 987 } | |
| 11190 | 988 if(!found) { |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
989 send_sip_response(sip->gc, msg, 501, "Not implemented", NULL); |
| 11190 | 990 } |
| 11341 | 991 } else { /* response */ |
| 11189 | 992 struct transaction *trans = transactions_find(sip, msg); |
| 993 if(trans) { | |
| 994 if(msg->response == 407) { | |
|
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
995 gchar *resend, *auth, *ptmp; |
|
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
996 |
| 11346 | 997 if(sip->proxy.retries>3) return; |
| 998 sip->proxy.retries++; | |
| 11341 | 999 /* do proxy authentication */ |
| 11189 | 1000 |
|
11439
617e67e1c985
[gaim-migrate @ 13676]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11424
diff
changeset
|
1001 ptmp = sipmsg_find_header(msg, "Proxy-Authenticate"); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1002 |
| 11189 | 1003 fill_auth(sip, ptmp, &sip->proxy); |
| 11346 | 1004 auth = auth_header(sip, &sip->proxy, trans->msg->method, trans->msg->target); |
| 11189 | 1005 sipmsg_remove_header(msg, "Proxy-Authorization"); |
| 1006 sipmsg_add_header(trans->msg, "Proxy-Authorization", auth); | |
| 1007 g_free(auth); | |
| 1008 resend = sipmsg_to_string(trans->msg); | |
| 11341 | 1009 /* resend request */ |
| 11189 | 1010 sendout_pkt(sip->gc, resend); |
| 1011 g_free(resend); | |
| 1012 } else { | |
| 11346 | 1013 sip->proxy.retries = 0; |
| 1014 if(msg->response == 401) sip->registrar.retries++; | |
| 1015 else sip->registrar.retries = 0; | |
| 11189 | 1016 if(trans->callback) { |
| 11341 | 1017 /* call the callback to process response*/ |
| 11189 | 1018 (trans->callback)(sip, msg, trans); |
| 1019 } | |
| 11194 | 1020 transactions_remove(sip, trans); |
| 11189 | 1021 } |
| 1022 found = 1; | |
| 1023 } else { | |
| 1024 gaim_debug(GAIM_DEBUG_MISC, "simple", "received response to unknown transaction"); | |
| 1025 } | |
| 1026 } | |
| 1027 if(!found) { | |
| 1028 gaim_debug(GAIM_DEBUG_MISC, "simple", "received a unknown sip message with method %sand response %d\n",msg->method, msg->response); | |
| 1029 } | |
| 1030 } | |
| 1031 | |
| 11181 | 1032 static void process_input(struct simple_account_data *sip, struct sip_connection *conn) |
| 1033 { | |
| 1034 char *cur; | |
| 1035 char *dummy; | |
| 1036 struct sipmsg *msg; | |
| 1037 int restlen; | |
| 1038 cur = conn->inbuf; | |
| 1039 | |
| 11341 | 1040 /* according to the RFC remove CRLF at the beginning */ |
| 11181 | 1041 while(*cur == '\r' || *cur == '\n') { |
| 1042 cur++; | |
| 1043 } | |
| 1044 if(cur != conn->inbuf) { | |
| 1045 memmove(conn->inbuf, cur, conn->inbufused-(cur-conn->inbuf)); | |
| 1046 conn->inbufused=strlen(conn->inbuf); | |
| 1047 } | |
| 1048 | |
| 11341 | 1049 /* Received a full Header? */ |
| 11181 | 1050 if((cur = strstr(conn->inbuf, "\r\n\r\n"))!=NULL) { |
| 1051 time_t currtime = time(NULL); | |
| 1052 cur += 2; | |
| 1053 cur[0] = '\0'; | |
| 1054 gaim_debug_info("simple","\n\nreceived - %s\n######\n%s\n#######\n\n",ctime(&currtime), conn->inbuf); | |
| 1055 msg = sipmsg_parse_header(conn->inbuf); | |
| 1056 cur[0] = '\r'; | |
| 1057 cur += 2; | |
| 1058 restlen = conn->inbufused - (cur-conn->inbuf); | |
| 1059 if(restlen>=msg->bodylen) { | |
| 1060 dummy = g_malloc(msg->bodylen+1); | |
| 1061 memcpy(dummy, cur, msg->bodylen); | |
| 1062 dummy[msg->bodylen]='\0'; | |
| 1063 msg->body = dummy; | |
| 1064 cur+=msg->bodylen; | |
| 1065 memmove(conn->inbuf, cur, conn->inbuflen); | |
| 1066 conn->inbufused=strlen(conn->inbuf); | |
| 1067 } else { | |
| 1068 sipmsg_free(msg); | |
| 1069 return; | |
| 1070 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1071 gaim_debug(GAIM_DEBUG_MISC, "simple", "in process response response: %d\n", msg->response); |
| 11189 | 1072 process_input_message(sip,msg); |
| 11181 | 1073 } else { |
| 1074 gaim_debug(GAIM_DEBUG_MISC, "simple", "received a incomplete sip msg: %s\n", conn->inbuf); | |
| 1075 } | |
| 1076 } | |
| 1077 | |
| 11189 | 1078 static void simple_udp_process(gpointer data, gint source, GaimInputCondition con) { |
| 1079 GaimConnection *gc = data; | |
| 1080 struct simple_account_data *sip = gc->proto_data; | |
| 1081 struct sipmsg *msg; | |
| 1082 int len; | |
| 1083 time_t currtime; | |
| 1084 | |
| 1085 static char buffer[65536]; | |
| 1086 len = recv(source, buffer, 65536, 0); | |
| 1087 buffer[len] = 0; | |
| 1088 gaim_debug_info("simple","\n\nreceived - %s\n######\n%s\n#######\n\n",ctime(&currtime), buffer); | |
| 1089 msg = sipmsg_parse_msg(buffer); | |
| 1090 if(msg) process_input_message(sip, msg); | |
| 1091 } | |
| 1092 | |
| 11181 | 1093 static void simple_input_cb(gpointer data, gint source, GaimInputCondition cond) |
| 1094 { | |
| 1095 GaimConnection *gc = data; | |
| 1096 struct simple_account_data *sip = gc->proto_data; | |
| 1097 int len; | |
| 1098 struct sip_connection *conn = connection_find(sip, source); | |
| 1099 if(!conn) { | |
| 1100 gaim_debug_error("simple", "Connection not found!\n"); | |
| 1101 return; | |
| 1102 } | |
| 1103 | |
| 1104 if (conn->inbuflen < conn->inbufused + SIMPLE_BUF_INC) { | |
| 1105 conn->inbuflen += SIMPLE_BUF_INC; | |
| 1106 conn->inbuf = g_realloc(conn->inbuf, conn->inbuflen); | |
| 1107 } | |
| 1108 | |
| 1109 if ((len = read(source, conn->inbuf + conn->inbufused, SIMPLE_BUF_INC - 1)) <= 0) { | |
| 1110 gaim_debug_info("simple","simple_input_cb: read error\n"); | |
| 1111 connection_remove(sip, source); | |
| 1112 if(sip->fd == source) sip->fd = -1; | |
| 1113 return; | |
| 1114 } | |
| 1115 if(len == 0) { | |
| 11341 | 1116 /* connection was closed */ |
| 11181 | 1117 connection_remove(sip, source); |
| 1118 if(sip->fd == source) sip->fd = -1; | |
| 1119 } | |
| 1120 | |
| 1121 conn->inbufused += len; | |
| 1122 conn->inbuf[conn->inbufused]='\0'; | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1123 |
| 11181 | 1124 process_input(sip, conn); |
| 1125 } | |
| 1126 | |
| 1127 /* Callback for new connections on incoming TCP port */ | |
| 1128 static void simple_newconn_cb(gpointer data, gint source, GaimInputCondition cond) { | |
| 1129 GaimConnection *gc = data; | |
| 1130 struct simple_account_data *sip = gc->proto_data; | |
| 1131 struct sip_connection *conn; | |
| 1132 | |
| 1133 int newfd = accept(source, NULL, NULL); | |
| 1134 | |
| 1135 conn = connection_create(sip, newfd); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1136 |
| 11181 | 1137 conn->inputhandler = gaim_input_add(newfd, GAIM_INPUT_READ, simple_input_cb, gc); |
| 1138 } | |
| 1139 | |
| 1140 static void login_cb(gpointer data, gint source, GaimInputCondition cond) { | |
| 1141 GaimConnection *gc = data; | |
| 1142 struct simple_account_data *sip = gc->proto_data; | |
| 1143 struct sip_connection *conn; | |
| 1144 | |
| 1145 if( source < 0 ) { | |
| 1146 gaim_connection_error(gc,"Could not connect"); | |
| 1147 return; | |
| 1148 } | |
| 1149 | |
| 1150 sip->fd = source; | |
| 1151 | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1152 conn = connection_create(sip, source); |
| 11181 | 1153 |
| 11341 | 1154 /* get the local ip */ |
| 11181 | 1155 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
|
1156 |
| 11194 | 1157 do_register(sip); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1158 |
| 11181 | 1159 conn->inputhandler = gaim_input_add(sip->fd, GAIM_INPUT_READ, simple_input_cb, gc); |
| 1160 } | |
| 1161 | |
| 1162 static guint simple_ht_hash_nick(const char *nick) { | |
| 1163 char *lc = g_utf8_strdown(nick, -1); | |
| 1164 guint bucket = g_str_hash(lc); | |
| 1165 g_free(lc); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1166 |
| 11181 | 1167 return bucket; |
| 1168 } | |
| 1169 | |
| 1170 static gboolean simple_ht_equals_nick(const char *nick1, const char *nick2) { | |
| 1171 return (gaim_utf8_strcasecmp(nick1, nick2) == 0); | |
| 1172 } | |
| 1173 | |
| 11383 | 1174 static void srvresolved(struct srv_response *resp, int results, gpointer data) { |
| 1175 struct simple_account_data *sip = (struct simple_account_data*) data; | |
| 1176 | |
| 1177 gchar *hostname; | |
| 1178 int port = 5060; | |
| 1179 | |
| 1180 int error = 0; | |
| 1181 struct sockaddr_in addr; | |
| 1182 struct hostent *h; | |
| 1183 | |
| 1184 /* find the host to connect to */ | |
| 1185 if(results) { | |
| 1186 hostname = g_strdup(resp->hostname); | |
| 1187 port = resp->port; | |
| 1188 g_free(resp); | |
| 1189 } else { | |
| 1190 if(!gaim_account_get_bool(sip->account, "useproxy", FALSE)) { | |
| 1191 hostname = g_strdup(sip->servername); | |
| 1192 } else { | |
| 1193 hostname = g_strdup(gaim_account_get_string(sip->account, "proxy", sip->servername)); | |
| 1194 } | |
| 1195 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1196 |
| 11383 | 1197 sip->realhostname = hostname; |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1198 sip->realport = port; |
| 11383 | 1199 /* TCP case */ |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1200 if(! sip->udp) { |
| 11409 | 1201 /* create socket for incoming connections */ |
| 1202 sip->listenfd = gaim_network_listen_range(5060, 5160); | |
| 1203 if(sip->listenfd == -1) { | |
| 1204 gaim_connection_error(sip->gc, _("Could not create listen socket")); | |
| 1205 return; | |
| 1206 } | |
| 1207 gaim_debug_info("simple", "listenfd: %d\n", sip->listenfd); | |
| 1208 sip->listenport = gaim_network_get_port_from_fd(sip->listenfd); | |
| 1209 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
|
1210 gaim_debug_info("simple","connecting to %s port %d\n", hostname, port); |
| 11383 | 1211 /* open tcp connection to the server */ |
| 1212 error = gaim_proxy_connect(sip->account, hostname, port, login_cb, sip->gc); | |
| 1213 if(error) { | |
| 1214 gaim_connection_error(sip->gc, _("Couldn't create socket")); | |
| 1215 } | |
| 1216 | |
| 1217 } else { /* UDP */ | |
| 1218 gaim_debug_info("simple", "using udp with server %s and port %d\n", hostname, port); | |
| 1219 sip->fd = socket(AF_INET, SOCK_DGRAM, 0); | |
| 1220 | |
| 1221 addr.sin_family = AF_INET; | |
| 1222 addr.sin_port = htons(5060); | |
| 1223 addr.sin_addr.s_addr = INADDR_ANY; | |
| 1224 while((bind(sip->fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) <0) && ntohs(addr.sin_port)<5160) { | |
| 1225 addr.sin_port = htons(ntohs(addr.sin_port)+1); | |
| 1226 } | |
| 1227 sip->listenport = ntohs(addr.sin_port); | |
| 1228 sip->listenfd = sip->fd; | |
| 1229 | |
| 1230 gaim_input_add(sip->fd, GAIM_INPUT_READ, simple_udp_process, sip->gc); | |
| 1231 sip->serveraddr.sin_family = AF_INET; | |
| 1232 sip->serveraddr.sin_port = htons(port); | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1233 |
| 11383 | 1234 h = gethostbyname(hostname); |
| 1235 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
|
1236 sip->ip = g_strdup(gaim_network_get_my_ip(sip->listenfd)); |
| 11383 | 1237 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
|
1238 do_register(sip); |
| 11383 | 1239 } |
| 1240 } | |
| 1241 | |
| 11181 | 1242 static void simple_login(GaimAccount *account, GaimStatus *status) |
| 1243 { | |
| 1244 GaimConnection *gc; | |
| 1245 struct simple_account_data *sip; | |
| 1246 gchar **userserver; | |
| 11210 | 1247 gchar *hosttoconnect; |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1248 |
| 11181 | 1249 const char *username = gaim_account_get_username(account); |
| 1250 | |
| 1251 gc = gaim_account_get_connection(account); | |
| 1252 gc->proto_data = sip = g_new0(struct simple_account_data,1); | |
| 1253 sip->gc=gc; | |
| 11189 | 1254 sip->account = account; |
| 11194 | 1255 sip->registerexpire = 900; |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1256 sip->udp = gaim_account_get_bool(account, "udp", FALSE); |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1257 if (strpbrk(username, " \t\v\r\n") != NULL) { |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1258 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
|
1259 return; |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1260 } |
| 11181 | 1261 |
| 1262 userserver = g_strsplit(username, "@", 2); | |
| 1263 gaim_connection_set_display_name(gc,userserver[0]); | |
| 1264 sip->username = g_strdup(userserver[0]); | |
| 1265 sip->servername = g_strdup(userserver[1]); | |
| 1266 sip->password = g_strdup(gaim_connection_get_password(gc)); | |
| 1267 g_strfreev(userserver); | |
| 1268 | |
| 1269 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
|
1270 |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1271 gaim_connection_update_progress(gc, _("Connecting"), 1, 2); |
| 11181 | 1272 |
| 1273 sip->status = g_strdup("available"); | |
| 11189 | 1274 |
| 11210 | 1275 if(!gaim_account_get_bool(account, "useproxy", FALSE)) { |
| 1276 hosttoconnect = g_strdup(sip->servername); | |
| 1277 } else { | |
| 1278 hosttoconnect = g_strdup(gaim_account_get_string(account, "proxy", sip->servername)); | |
| 1279 } | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1280 |
| 11341 | 1281 /* TCP case */ |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1282 if(! sip->udp) { |
| 11383 | 1283 gaim_srv_resolve("sip","tcp",hosttoconnect,srvresolved, sip); |
| 11341 | 1284 } else { /* UDP */ |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1285 gaim_srv_resolve("sip","udp",hosttoconnect,srvresolved, sip); |
| 11181 | 1286 } |
| 11210 | 1287 g_free(hosttoconnect); |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1288 |
| 11341 | 1289 /* register timeout callback for register / subscribe renewal */ |
| 11194 | 1290 sip->registertimeout = gaim_timeout_add((rand()%100)+10*1000, (GSourceFunc)register_timeout, sip); |
| 11181 | 1291 } |
| 1292 | |
| 1293 static void simple_close(GaimConnection *gc) | |
| 1294 { | |
| 1295 struct simple_account_data *sip = gc->proto_data; | |
| 11194 | 1296 |
| 11341 | 1297 /* unregister */ |
| 11194 | 1298 do_register_exp(sip, 0); |
| 11346 | 1299 connection_free_all(sip); |
| 11341 | 1300 if(sip) { |
| 11181 | 1301 if(sip->servername) g_free(sip->servername); |
| 1302 if(sip->username) g_free(sip->username); | |
| 1303 if(sip->password) g_free(sip->password); | |
| 1304 if(sip->registrar.nonce) g_free(sip->registrar.nonce); | |
| 11341 | 1305 if(sip->registrar.realm) g_free(sip->registrar.realm); |
| 11181 | 1306 if(sip->proxy.nonce) g_free(sip->proxy.nonce); |
| 1307 if(sip->proxy.realm) g_free(sip->proxy.realm); | |
| 1308 if(sip->sendlater) g_free(sip->sendlater); | |
| 1309 if(sip->ip) g_free(sip->ip); | |
| 11383 | 1310 if(sip->realhostname) g_free(sip->realhostname); |
| 11409 | 1311 if(sip->listenpa) gaim_input_remove(sip->listenpa); |
| 11346 | 1312 if(sip->registertimeout) gaim_timeout_remove(sip->registertimeout); |
| 11383 | 1313 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 | 1314 } |
| 11341 | 1315 if(gc->proto_data) g_free(gc->proto_data); |
| 1316 gc->proto_data = 0; | |
| 11181 | 1317 } |
| 1318 | |
| 11345 | 1319 /* not needed since privacy is checked for every subscribe */ |
| 1320 static void dummy_add_deny(GaimConnection *gc, const char *name) { | |
| 1321 } | |
| 1322 | |
| 1323 static void dummy_permit_deny(GaimConnection *gc) { | |
| 1324 } | |
| 1325 | |
| 11181 | 1326 static GaimPluginProtocolInfo prpl_info = |
| 1327 { | |
| 1328 0, | |
| 1329 NULL, /* user_splits */ | |
| 1330 NULL, /* protocol_options */ | |
| 1331 NO_BUDDY_ICONS, /* icon_spec */ | |
| 1332 simple_list_icon, /* list_icon */ | |
| 1333 NULL, /* list_emblems */ | |
| 1334 NULL, /* status_text */ | |
| 1335 NULL, /* tooltip_text */ | |
| 1336 simple_status_types, /* away_states */ | |
| 1337 NULL, /* blist_node_menu */ | |
| 1338 NULL, /* chat_info */ | |
| 1339 NULL, /* chat_info_defaults */ | |
| 1340 simple_login, /* login */ | |
| 1341 simple_close, /* close */ | |
| 1342 simple_im_send, /* send_im */ | |
| 1343 NULL, /* set_info */ | |
| 1344 simple_typing, /* send_typing */ | |
| 1345 NULL, /* get_info */ | |
| 1346 simple_set_status, /* set_status */ | |
| 1347 NULL, /* set_idle */ | |
| 1348 NULL, /* change_passwd */ | |
| 1349 simple_add_buddy, /* add_buddy */ | |
| 1350 NULL, /* add_buddies */ | |
| 1351 simple_remove_buddy, /* remove_buddy */ | |
| 1352 NULL, /* remove_buddies */ | |
| 11345 | 1353 dummy_add_deny, /* add_permit */ |
| 1354 dummy_add_deny, /* add_deny */ | |
| 1355 dummy_add_deny, /* rem_permit */ | |
| 1356 dummy_add_deny, /* rem_deny */ | |
| 1357 dummy_permit_deny, /* set_permit_deny */ | |
| 11181 | 1358 NULL, /* join_chat */ |
| 1359 NULL, /* reject_chat */ | |
| 1360 NULL, /* get_chat_name */ | |
| 1361 NULL, /* chat_invite */ | |
| 1362 NULL, /* chat_leave */ | |
| 1363 NULL, /* chat_whisper */ | |
| 1364 NULL, /* chat_send */ | |
| 1365 simple_keep_alive, /* keepalive */ | |
| 1366 NULL, /* register_user */ | |
| 1367 NULL, /* get_cb_info */ | |
| 1368 NULL, /* get_cb_away */ | |
| 1369 NULL, /* alias_buddy */ | |
| 1370 NULL, /* group_buddy */ | |
| 1371 NULL, /* rename_group */ | |
| 1372 NULL, /* buddy_free */ | |
| 1373 NULL, /* convo_closed */ | |
| 1374 NULL, /* normalize */ | |
| 1375 NULL, /* set_buddy_icon */ | |
| 1376 NULL, /* remove_group */ | |
| 1377 NULL, /* get_cb_real_name */ | |
| 1378 NULL, /* set_chat_topic */ | |
| 1379 NULL, /* find_blist_chat */ | |
| 1380 NULL, /* roomlist_get_list */ | |
| 1381 NULL, /* roomlist_cancel */ | |
| 1382 NULL, /* roomlist_expand_category */ | |
| 1383 NULL, /* can_receive_file */ | |
| 1384 NULL /* send_file */ | |
| 1385 }; | |
| 1386 | |
| 1387 | |
| 1388 static GaimPluginInfo info = | |
| 1389 { | |
| 1390 GAIM_PLUGIN_MAGIC, | |
| 1391 GAIM_MAJOR_VERSION, | |
| 1392 GAIM_MINOR_VERSION, | |
| 1393 GAIM_PLUGIN_PROTOCOL, /**< type */ | |
| 1394 NULL, /**< ui_requirement */ | |
| 1395 0, /**< flags */ | |
| 1396 NULL, /**< dependencies */ | |
| 1397 GAIM_PRIORITY_DEFAULT, /**< priority */ | |
| 1398 | |
| 1399 "prpl-simple", /**< id */ | |
| 1400 "SIMPLE", /**< name */ | |
| 1401 VERSION, /**< version */ | |
| 1402 N_("SIP/SIMPLE Protocol Plugin"), /** summary */ | |
| 1403 N_("The SIP/SIMPLE Protocol Plugin"), /** description */ | |
| 1404 N_("Thomas Butter <butter@uni-mannheim.de>"), /**< author */ | |
| 1405 GAIM_WEBSITE, /**< homepage */ | |
| 1406 | |
| 1407 NULL, /**< load */ | |
| 1408 NULL, /**< unload */ | |
| 1409 NULL, /**< destroy */ | |
| 1410 | |
| 1411 NULL, /**< ui_info */ | |
| 1412 &prpl_info, /**< extra_info */ | |
| 1413 NULL, | |
| 1414 NULL | |
| 1415 }; | |
| 1416 | |
| 1417 static void _init_plugin(GaimPlugin *plugin) | |
| 1418 { | |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1419 GaimAccountUserSplit *split; |
| 11189 | 1420 GaimAccountOption *option; |
| 11181 | 1421 |
|
11396
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1422 split = gaim_account_user_split_new(_("Server"), "", '@'); |
|
be776f9b1818
[gaim-migrate @ 13627]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11383
diff
changeset
|
1423 prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); |
| 11181 | 1424 |
| 11345 | 1425 option = gaim_account_option_bool_new(_("Publish Status (note: everyone may watch you)"), "dopublish", TRUE); |
| 1426 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
| 1427 | |
| 11189 | 1428 option = gaim_account_option_bool_new(_("Use UDP"), "udp", FALSE); |
| 1429 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
| 11210 | 1430 option = gaim_account_option_bool_new(_("Use Proxy"), "useproxy", FALSE); |
| 1431 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
| 1432 option = gaim_account_option_string_new(_("Proxy"), "proxy", ""); | |
| 1433 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); | |
| 11181 | 1434 } |
| 1435 | |
| 1436 GAIM_INIT_PLUGIN(simple, _init_plugin, info); |
