comparison src/protocols/zephyr/zephyr.c @ 9896:a806e5150eca

[gaim-migrate @ 10785] " summary: This patch adds support for a zephyr proxy tzc. User visible changes will be an options check box to enable tzc, and a text box with the command to run tzc. %s in the command would be replaced by the user's exposure (visibility) level. e.g ssh username@host tzc -e %s Details: What is tzc: tzc aka "trivial zephyr client", is a zephyr helper program, designed originally for use with emacs-zephyr (it takes as input and outputs lisp expressions), and also used as the backend for kzephyr. Why? It is often invoked by a zephyr using on a remote host, by doing ssh username@host tzc -e EXPOSURE so that one can use any of the zephyr clients that use it as a backend, behind NAT "routers" and firewalls, which will generally block zephyr. Also, people will not have to recompile gaim, or have a working zephyr setup as is currently needed - they can merely set the tzc command to a run tzc from a remote host which has zephyr and tzc installed -- most zephyr users are at universities where they have access to such a machine. Where can one get tzc? I tested this against the version (2.6.15-zml) available here: http://www.club.cc.cmu.edu/debian/dists/stable/contrib/source/tzc-cclub_001-3.tar.gz Some older versions won't support buddylists. A lot of the parsing code was borrowed (and converted from C++ to C) from kzephyr (http://www-2.cs.cmu.edu/~colohan/kzephyr/), a GPL'd zephyr client. And tzc is also GPL'd, FWIW." --Arun A Tharuvai committer: Tailor Script <tailor@pidgin.im>
author Luke Schierer <lschiere@pidgin.im>
date Sat, 28 Aug 2004 02:25:16 +0000
parents c28d5b45624e
children 4f1fcf5efaf9
comparison
equal deleted inserted replaced
9895:1dfebce5eac9 9896:a806e5150eca
5 * Copyright (C) 1998-2001, Mark Spencer <markster@marko.net> 5 * Copyright (C) 1998-2001, Mark Spencer <markster@marko.net>
6 * Some code borrowed from GtkZephyr, by 6 * Some code borrowed from GtkZephyr, by
7 * Jag/Sean Dilda <agrajag@linuxpower.org>/<smdilda@unity.ncsu.edu> 7 * Jag/Sean Dilda <agrajag@linuxpower.org>/<smdilda@unity.ncsu.edu>
8 * http://gtkzephyr.linuxpower.org/ 8 * http://gtkzephyr.linuxpower.org/
9 * 9 *
10 * Some code borrowed from kzephyr, by
11 * Chris Colohan <colohan+@cs.cmu.edu>
12 *
10 * This program is free software; you can redistribute it and/or modify 13 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by 14 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or 15 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version. 16 * (at your option) any later version.
14 * 17 *
15 * This program is distributed in the hope that it will be useful, 18 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details. 21 * GNU General Public License for more details.
19 * 22 *
20 * You should have received a copy of the GNU General Public License 23 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software 24 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * 26 *
24 */ 27
28 */
25 /* XXX eww */ 29 /* XXX eww */
26 #include "src/internal.h" 30 #include "src/internal.h"
27 31
28 #include "accountopt.h" 32 #include "accountopt.h"
29 #include "debug.h" 33 #include "debug.h"
30 #include "notify.h" 34 #include "notify.h"
31 #include "prpl.h" 35 #include "prpl.h"
32 #include "server.h" 36 #include "server.h"
33 #include "util.h" 37 #include "util.h"
34 #include "cmds.h" 38 #include "cmds.h"
35 39 #include "privacy.h"
36 #include "zephyr/zephyr.h" 40
41 #include "zephyr.h"
37 #include "internal.h" 42 #include "internal.h"
38 43
39 #include <strings.h> 44 #include <strings.h>
40 45
41 #define ZEPHYR_FALLBACK_CHARSET "ISO-8859-1" 46 #define ZEPHYR_FALLBACK_CHARSET "ISO-8859-1"
42 47
43 /* these are deliberately high, since most people don't send multiple "PING"s */ 48 /* these are deliberately high, since most people don't send multiple "PING"s */
44 #define ZEPHYR_TYPING_SEND_TIMEOUT 15 49 #define ZEPHYR_TYPING_SEND_TIMEOUT 15
45 #define ZEPHYR_TYPING_RECV_TIMEOUT 10 50 #define ZEPHYR_TYPING_RECV_TIMEOUT 10
51 #define ZEPHYR_FD_READ 0
52 #define ZEPHYR_FD_WRITE 1
46 53
47 extern Code_t ZGetLocations(ZLocations_t *, int *); 54 extern Code_t ZGetLocations(ZLocations_t *, int *);
48 extern Code_t ZSetLocation(char *); 55 extern Code_t ZSetLocation(char *);
49 extern Code_t ZUnsetLocation(); 56 extern Code_t ZUnsetLocation();
50 extern Code_t ZGetSubscriptions(ZSubscription_t *, int*); 57 extern Code_t ZGetSubscriptions(ZSubscription_t *, int*);
51 58
52 typedef struct _zframe zframe; 59 typedef struct _zframe zframe;
53 typedef struct _zephyr_triple zephyr_triple; 60 typedef struct _zephyr_triple zephyr_triple;
54 typedef struct _zephyr_account zephyr_account; 61 typedef struct _zephyr_account zephyr_account;
55 62 typedef struct _parse_tree parse_tree;
63
64 typedef enum {
65 GAIM_ZEPHYR_NONE, /* Non-kerberized ZEPH0.2 */
66 GAIM_ZEPHYR_KRB4, /* ZEPH0.2 w/ KRB4 support */
67 GAIM_ZEPHYR_TZC, /* tzc executable proxy */
68 GAIM_ZEPHYR_INTERGALACTIC_KRB4, /* Kerberized ZEPH0.3 */
69 } zephyr_connection_type;
56 70
57 struct _zephyr_account { 71 struct _zephyr_account {
58 GaimAccount* account; 72 GaimAccount* account;
59 char *username; 73 char *username;
60 char* realm; 74 char *realm;
61 char* galaxy; 75 char *encoding;
62 char* krbtkfile; 76 char* galaxy; /* not yet useful */
63 guint32 nottimer; 77 char* krbtkfile; /* not yet useful */
64 guint32 loctimer; 78 guint32 nottimer;
65 GList *pending_zloc_names; 79 guint32 loctimer;
66 GSList *subscrips; 80 GList *pending_zloc_names;
67 int last_id; 81 GSList *subscrips;
68 unsigned short port; 82 int last_id;
69 char ourhost[HOST_NAME_MAX + 1]; 83 unsigned short port;
70 char ourhostcanon[HOST_NAME_MAX + 1]; 84 char ourhost[HOST_NAME_MAX + 1];
85 char ourhostcanon[HOST_NAME_MAX + 1];
86 zephyr_connection_type connection_type;
87 int totzc[2];
88 int fromtzc[2];
89 char *exposure;
90 pid_t tzc_pid;
71 }; 91 };
92
93 #define MAXCHILDREN 20
94
95 struct _parse_tree {
96 gchar* contents;
97 parse_tree *children[MAXCHILDREN];
98 int num_children;
99 };
100
101 parse_tree null_parse_tree = {
102 "",
103 {},
104 0,
105 };
106
107 #define use_none(zephyr) ((zephyr->connection_type == GAIM_ZEPHYR_NONE)?1:0)
108 #define use_krb4(zephyr) ((zephyr->connection_type == GAIM_ZEPHYR_KRB4)?1:0)
109 #define use_tzc(zephyr) ((zephyr->connection_type == GAIM_ZEPHYR_TZC)?1:0)
110
111 #define use_zeph02(zephyr) ( (zephyr->connection_type == GAIM_ZEPHYR_NONE)?1: ((zephyr->connection_type == GAIM_ZEPHYR_KRB4)?1:0))
72 112
73 /* struct I need for zephyr_to_html */ 113 /* struct I need for zephyr_to_html */
74 struct _zframe { 114 struct _zframe {
75 /* true for everything but @color, since inside the parens of that one is 115 /* true for everything but @color, since inside the parens of that one is
76 * the color. */ 116 * the color. */
93 133
94 #define z_call(func) if (func != ZERR_NONE)\ 134 #define z_call(func) if (func != ZERR_NONE)\
95 return; 135 return;
96 #define z_call_r(func) if (func != ZERR_NONE)\ 136 #define z_call_r(func) if (func != ZERR_NONE)\
97 return TRUE; 137 return TRUE;
138
98 #define z_call_s(func, err) if (func != ZERR_NONE) {\ 139 #define z_call_s(func, err) if (func != ZERR_NONE) {\
99 gaim_connection_error(gc, err);\ 140 gaim_connection_error(gc, err);\
100 return;\ 141 return;\
101 } 142 }
102 143
103 char *local_zephyr_normalize(const char *); 144
145 Code_t zephyr_subscribe_to(zephyr_account* zephyr, char* class, char *instance, char *recipient, char* galaxy) {
146
147 if (use_tzc(zephyr)) {
148 /* ((tzcfodder . subscribe) ("class" "instance" "recipient")) */
149 gchar *zsubstr = g_strdup_printf("((tzcfodder . subscribe) (\"%s\" \"%s\" \"%s\"))\n",class,instance,recipient);
150 write(zephyr->totzc[ZEPHYR_FD_WRITE],zsubstr,strlen(zsubstr));
151 g_free(zsubstr);
152 return ZERR_NONE;
153 }
154 else {
155 if (use_zeph02(zephyr)) {
156 ZSubscription_t sub;
157 sub.zsub_class = class;
158 sub.zsub_classinst = instance;
159 sub.zsub_recipient = recipient;
160 return ZSubscribeTo(&sub,1,0);
161 } else {
162 /* This should not happen */
163 return -1;
164 }
165 }
166 return -1;
167 }
168
169 char *local_zephyr_normalize(zephyr_account* zephyr,const char *);
104 static const char *zephyr_normalize(const GaimAccount *, const char *); 170 static const char *zephyr_normalize(const GaimAccount *, const char *);
105 static const char *gaim_zephyr_get_realm();
106 static void zephyr_chat_set_topic(GaimConnection * gc, int id, const char *topic); 171 static void zephyr_chat_set_topic(GaimConnection * gc, int id, const char *topic);
107 172 char* zephyr_tzc_deescape_str(const char *message);
108 char *zephyr_strip_foreign_realm(const char* user){ 173
109 /* 174 char *zephyr_strip_foreign_realm(zephyr_account* zephyr,const char* user){
110 Takes in a username of the form username or username@realm 175 /*
111 and returns: 176 Takes in a username of the form username or username@realm
112 username, if there is no realm, or the realm is the local realm 177 and returns:
113 or: 178 username, if there is no realm, or the realm is the local realm
114 username@realm if there is a realm and it is foreign 179 or:
115 */ 180 username@realm if there is a realm and it is foreign
181 */
116 char *tmp = g_strdup(user); 182 char *tmp = g_strdup(user);
117 char *at = strchr(tmp,'@'); 183 char *at = strchr(tmp,'@');
118 if (at && !g_ascii_strcasecmp(at+1,gaim_zephyr_get_realm())) { 184 if (at && !g_ascii_strcasecmp(at+1,zephyr->realm)) {
119 /* We're passed in a username of the form user@users-realm */ 185 /* We're passed in a username of the form user@users-realm */
120 char* tmp2; 186 char* tmp2;
121 *at = '\0'; 187 *at = '\0';
122 tmp2 = g_strdup(tmp); 188 tmp2 = g_strdup(tmp);
123 g_free(tmp); 189 g_free(tmp);
169 g_free(zt->recipient); 235 g_free(zt->recipient);
170 g_free(zt->name); 236 g_free(zt->name);
171 g_free(zt); 237 g_free(zt);
172 } 238 }
173 239
174 static gchar *gaim_zephyr_get_sender()
175 {
176 /* will be useful once this plugin can use a backend other
177 than libzephyr */
178 /* XXX add zephyr error reporting */
179 gchar *sender;
180 sender = ZGetSender();
181 if (!sender || !g_ascii_strcasecmp(sender,"")) {
182 sender = "";
183 }
184 return sender;
185 }
186
187 static const char *gaim_zephyr_get_realm()
188 {
189 /* will be useful once this plugin can use a backend other
190 than libzephyr */
191 gchar *realm=NULL;
192 /* XXX add zephyr error reporting */
193 realm= ZGetRealm();
194 return realm;
195 }
196
197 /* returns true if zt1 is a subset of zt2. This function is used to 240 /* returns true if zt1 is a subset of zt2. This function is used to
198 determine whether a zephyr sent to zt1 should be placed in the chat 241 determine whether a zephyr sent to zt1 should be placed in the chat
199 with triple zt2 242 with triple zt2
200 243
201 zt1 is a subset of zt2 244 zt1 is a subset of zt2
204 AND. the recipient names are identical 247 AND. the recipient names are identical
205 */ 248 */
206 249
207 static gboolean triple_subset(zephyr_triple * zt1, zephyr_triple * zt2) 250 static gboolean triple_subset(zephyr_triple * zt1, zephyr_triple * zt2)
208 { 251 {
252
253 if (!zt2)
254 gaim_debug_error("zephyr","zt2 doesn't exist\n");
255 if (!zt1)
256 gaim_debug_error("zephyr","zt1 doesn't exist\n");
257 if (!(zt1->class))
258 gaim_debug_error("zephyr","zt1c doesn't exist\n");
259 if (!(zt1->instance))
260 gaim_debug_error("zephyr","zt1i doesn't exist\n");
261 if (!(zt1->recipient))
262 gaim_debug_error("zephyr","zt1r doesn't exist\n");
263 if (!(zt2->class))
264 gaim_debug_error("zephyr","zt2c doesn't exist\n");
265 if (!(zt2->recipient))
266 gaim_debug_error("zephyr","zt2r doesn't exist\n");
267 if (!(zt2->instance))
268 gaim_debug_error("zephyr","zt2i doesn't exist\n");
269
270
209 if (g_ascii_strcasecmp(zt2->class, zt1->class)) { 271 if (g_ascii_strcasecmp(zt2->class, zt1->class)) {
210 return FALSE; 272 return FALSE;
211 } 273 }
212 if (g_ascii_strcasecmp(zt2->instance, zt1->instance) && g_ascii_strcasecmp(zt2->instance, "*")) { 274 if (g_ascii_strcasecmp(zt2->instance, zt1->instance) && g_ascii_strcasecmp(zt2->instance, "*")) {
213 return FALSE; 275 return FALSE;
214 } 276 }
215 if (g_ascii_strcasecmp(zt2->recipient, zt1->recipient)) { 277 if (g_ascii_strcasecmp(zt2->recipient, zt1->recipient)) {
216 return FALSE; 278 return FALSE;
217 } 279 }
280 gaim_debug_info("zephyr","<%s,%s,%s> is in <%s,%s,%s>\n",zt1->class,zt1->instance,zt1->recipient,zt2->class,zt2->instance,zt2->recipient);
218 return TRUE; 281 return TRUE;
219 } 282 }
220 283
221 static zephyr_triple *find_sub_by_triple(zephyr_account *zephyr,zephyr_triple * zt) 284 static zephyr_triple *find_sub_by_triple(zephyr_account *zephyr,zephyr_triple * zt)
222 { 285 {
252 315
253 static gchar *zephyr_recv_convert(GaimConnection *gc,gchar *string, int len) 316 static gchar *zephyr_recv_convert(GaimConnection *gc,gchar *string, int len)
254 { 317 {
255 gchar *utf8; 318 gchar *utf8;
256 GError *err = NULL; 319 GError *err = NULL;
257 320 zephyr_account *zephyr = gc->proto_data;
258 if (g_utf8_validate(string, len, NULL)) { 321 if (g_utf8_validate(string, len, NULL)) {
259 return g_strdup(string); 322 return g_strdup(string);
260 } else { 323 } else {
261 utf8 = g_convert(string, len, "UTF-8", gaim_account_get_string(gc->account, "encoding", ZEPHYR_FALLBACK_CHARSET), NULL, NULL, &err); 324 utf8 = g_convert(string, len, "UTF-8", zephyr->encoding, NULL, NULL, &err);
262 if (err) { 325 if (err) {
263 gaim_debug(GAIM_DEBUG_ERROR, "zephyr", "recv conversion error: %s\n", err->message); 326 gaim_debug(GAIM_DEBUG_ERROR, "zephyr", "recv conversion error: %s\n", err->message);
264 utf8 = g_strdup(_("(There was an error converting this message. Check the 'Encoding' option in the Account Editor)")); 327 utf8 = g_strdup(_("(There was an error converting this message. Check the 'Encoding' option in the Account Editor)"));
265 g_error_free(err); 328 g_error_free(err);
266 } 329 }
267 330
268 return utf8; 331 return utf8;
269 } 332 }
297 ret = g_new0(char, len * 3); 360 ret = g_new0(char, len * 3);
298 361
299 bzero(ret, len * 3); 362 bzero(ret, len * 3);
300 retcount = 0; 363 retcount = 0;
301 cnt = 0; 364 cnt = 0;
365 gaim_debug_info("zephyr","html received %s\n",message);
302 while (cnt <= len) { 366 while (cnt <= len) {
303 if (message[cnt] == '<') { 367 if (message[cnt] == '<') {
304 if (!g_ascii_strncasecmp(message + cnt + 1, "i>", 2)) { 368 if (!g_ascii_strncasecmp(message + cnt + 1, "i>", 2)) {
305 strncpy(ret + retcount, "@i(", 3); 369 strncpy(ret + retcount, "@i(", 3);
306 cnt += 3; 370 cnt += 3;
311 retcount += 3; 375 retcount += 3;
312 } else if (!g_ascii_strncasecmp(message + cnt + 1, "br>", 3)) { 376 } else if (!g_ascii_strncasecmp(message + cnt + 1, "br>", 3)) {
313 strncpy(ret + retcount, "\n", 1); 377 strncpy(ret + retcount, "\n", 1);
314 cnt += 4; 378 cnt += 4;
315 retcount += 1; 379 retcount += 1;
380 } else if (!g_ascii_strncasecmp(message + cnt + 1, "a href=\"mailto:", 15)) {
381 cnt += 16;
382 while (g_ascii_strncasecmp(message + cnt, "\">", 2) != 0) {
383 ret[retcount] = message[cnt];
384 retcount++;
385 cnt++;
386 }
387 cnt += 2;
388 /* ignore descriptive string */
389 while (g_ascii_strncasecmp(message + cnt, "</a>", 4) != 0) {
390 cnt++;
391 }
392 cnt += 4;
316 } else if (!g_ascii_strncasecmp(message + cnt + 1, "a href=\"", 8)) { 393 } else if (!g_ascii_strncasecmp(message + cnt + 1, "a href=\"", 8)) {
317 cnt += 9; 394 cnt += 9;
318 while (g_ascii_strncasecmp(message + cnt, "\">", 2) != 0) { 395 while (g_ascii_strncasecmp(message + cnt, "\">", 2) != 0) {
319 ret[retcount] = message[cnt]; 396 ret[retcount] = message[cnt];
320 retcount++; 397 retcount++;
358 cnt += 6; 435 cnt += 6;
359 if ((message[cnt] == '1') || (message[cnt] == '2')) { 436 if ((message[cnt] == '1') || (message[cnt] == '2')) {
360 strncpy(ret + retcount, "@small(", 7); 437 strncpy(ret + retcount, "@small(", 7);
361 retcount += 7; 438 retcount += 7;
362 } else if ((message[cnt] == '3') 439 } else if ((message[cnt] == '3')
363 || (message[cnt] == '4')) { 440 || (message[cnt] == '4')) {
364 strncpy(ret + retcount, "@medium(", 8); 441 strncpy(ret + retcount, "@medium(", 8);
365 retcount += 8; 442 retcount += 8;
366 } else if ((message[cnt] == '5') 443 } else if ((message[cnt] == '5')
367 || (message[cnt] == '6') 444 || (message[cnt] == '6')
368 || (message[cnt] == '7')) { 445 || (message[cnt] == '7')) {
369 strncpy(ret + retcount, "@large(", 7); 446 strncpy(ret + retcount, "@large(", 7);
370 retcount += 7; 447 retcount += 7;
371 } 448 }
372 cnt += 3; 449 cnt += 3;
373 } else { 450 } else {
376 cnt++; 453 cnt++;
377 } 454 }
378 cnt += 2; 455 cnt += 2;
379 } 456 }
380 } else if (!g_ascii_strncasecmp(message + cnt + 1, "/i>", 3) 457 } else if (!g_ascii_strncasecmp(message + cnt + 1, "/i>", 3)
381 || !g_ascii_strncasecmp(message + cnt + 1, "/b>", 3)) { 458 || !g_ascii_strncasecmp(message + cnt + 1, "/b>", 3)) {
382 cnt += 4; 459 cnt += 4;
383 ret[retcount] = ')'; 460 ret[retcount] = ')';
384 retcount++; 461 retcount++;
385 } else if (!g_ascii_strncasecmp(message + cnt + 1, "/font>", 6)) { 462 } else if (!g_ascii_strncasecmp(message + cnt + 1, "/font>", 6)) {
386 cnt += 7; 463 cnt += 7;
399 ret[retcount] = message[cnt]; 476 ret[retcount] = message[cnt];
400 retcount++; 477 retcount++;
401 cnt++; 478 cnt++;
402 } 479 }
403 } 480 }
481 gaim_debug_info("zephyr","zephyr outputted %s\n",ret);
404 return ret; 482 return ret;
405 } 483 }
406 484
407 /* this parses zephyr formatting and converts it to html. For example, if 485 /* this parses zephyr formatting and converts it to html. For example, if
408 * you pass in "@{@color(blue)@i(hello)}" you should get out 486 * you pass in "@{@color(blue)@i(hello)}" you should get out
426 zframe *new_f; 504 zframe *new_f;
427 char *buf; 505 char *buf;
428 int end; 506 int end;
429 507
430 for (end = 1; (cnt + end) <= len && !IS_OPENER(message[cnt + end]) 508 for (end = 1; (cnt + end) <= len && !IS_OPENER(message[cnt + end])
431 && !IS_CLOSER(message[cnt + end]); end++); 509 && !IS_CLOSER(message[cnt + end]); end++);
432 buf = g_new0(char, end); 510 buf = g_new0(char, end);
433 511
434 if (end) { 512 if (end) {
435 g_snprintf(buf, end, "%s", message + cnt + 1); 513 g_snprintf(buf, end, "%s", message + cnt + 1);
436 } 514 }
462 new_f->text = g_string_new("<font size=\"7\">"); 540 new_f->text = g_string_new("<font size=\"7\">");
463 new_f->closing = "</font>"; 541 new_f->closing = "</font>";
464 frames = new_f; 542 frames = new_f;
465 cnt += end + 1; 543 cnt += end + 1;
466 } else if (!g_ascii_strcasecmp(buf, "bold") 544 } else if (!g_ascii_strcasecmp(buf, "bold")
467 || !g_ascii_strcasecmp(buf, "b")) { 545 || !g_ascii_strcasecmp(buf, "b")) {
468 new_f = g_new(zframe, 1); 546 new_f = g_new(zframe, 1);
469 new_f->enclosing = frames; 547 new_f->enclosing = frames;
470 new_f->text = g_string_new("<b>"); 548 new_f->text = g_string_new("<b>");
471 new_f->closing = "</b>"; 549 new_f->closing = "</b>";
472 new_f->has_closer = TRUE; 550 new_f->has_closer = TRUE;
511 g_string_append_c(frames->text, '@'); 589 g_string_append_c(frames->text, '@');
512 cnt++; 590 cnt++;
513 } else if (IS_CLOSER(message[cnt + end])) { 591 } else if (IS_CLOSER(message[cnt + end])) {
514 /* We have @chars..closer . This is 592 /* We have @chars..closer . This is
515 merely a sequence of chars that isn't a formatting tag 593 merely a sequence of chars that isn't a formatting tag
516 */ 594 */
517 int tmp = cnt; 595 int tmp = cnt;
518 596
519 while (tmp <= cnt + end) { 597 while (tmp <= cnt + end) {
520 g_string_append_c(frames->text, message[tmp]); 598 g_string_append_c(frames->text, message[tmp]);
521 tmp++; 599 tmp++;
577 static gboolean pending_zloc(zephyr_account *zephyr,char *who) 655 static gboolean pending_zloc(zephyr_account *zephyr,char *who)
578 { 656 {
579 GList *curr; 657 GList *curr;
580 658
581 for (curr = zephyr->pending_zloc_names; curr != NULL; curr = curr->next) { 659 for (curr = zephyr->pending_zloc_names; curr != NULL; curr = curr->next) {
582 char* normalized_who = local_zephyr_normalize(who); 660 char* normalized_who = local_zephyr_normalize(zephyr,who);
583 if (!g_ascii_strcasecmp(normalized_who, (char *)curr->data)) { 661 if (!g_ascii_strcasecmp(normalized_who, (char *)curr->data)) {
584 g_free((char *)curr->data); 662 g_free((char *)curr->data);
585 zephyr->pending_zloc_names = g_list_remove(zephyr->pending_zloc_names, curr->data); 663 zephyr->pending_zloc_names = g_list_remove(zephyr->pending_zloc_names, curr->data);
586 return TRUE; 664 return TRUE;
587 } 665 }
602 } 680 }
603 } 681 }
604 682
605 static void handle_message(GaimConnection *gc,ZNotice_t notice, struct sockaddr_in from) 683 static void handle_message(GaimConnection *gc,ZNotice_t notice, struct sockaddr_in from)
606 { 684 {
685 zephyr_account* zephyr = gc->proto_data;
686
607 if (!g_ascii_strcasecmp(notice.z_class, LOGIN_CLASS)) { 687 if (!g_ascii_strcasecmp(notice.z_class, LOGIN_CLASS)) {
608 /* well, we'll be updating in 20 seconds anyway, might as well ignore this. */ 688 /* well, we'll be updating in 20 seconds anyway, might as well ignore this. */
609 } else if (!g_ascii_strcasecmp(notice.z_class, LOCATE_CLASS)) { 689 } else if (!g_ascii_strcasecmp(notice.z_class, LOCATE_CLASS)) {
610 if (!g_ascii_strcasecmp(notice.z_opcode, LOCATE_LOCATE)) { 690 if (!g_ascii_strcasecmp(notice.z_opcode, LOCATE_LOCATE)) {
611 int nlocs; 691 int nlocs;
612 char *user; 692 char *user;
613 GaimBuddy *b; 693 GaimBuddy *b;
614
615 /* XXX add real error reporting */ 694 /* XXX add real error reporting */
616 if (ZParseLocations(&notice, NULL, &nlocs, &user) != ZERR_NONE) 695 if (ZParseLocations(&notice, NULL, &nlocs, &user) != ZERR_NONE)
617 return; 696 return;
618 697
619 if ((b = gaim_find_buddy(gc->account, user)) == NULL) { 698 if ((b = gaim_find_buddy(gc->account, user)) == NULL) {
620 char *e = strchr(user, '@'); 699 char *e = strchr(user, '@');
621 700
622 if (e && !g_ascii_strcasecmp(e + 1, gaim_zephyr_get_realm())) { 701 if (e && !g_ascii_strcasecmp(e + 1, zephyr->realm)) {
623 *e = '\0'; 702 *e = '\0';
624 } 703 }
625 b = gaim_find_buddy(gc->account, user); 704 b = gaim_find_buddy(gc->account, user);
626 } 705 }
627 if ((b && pending_zloc(gc->proto_data,b->name)) || pending_zloc(gc->proto_data,user)) { 706 if ((b && pending_zloc(zephyr,b->name)) || pending_zloc(zephyr,user)) {
628 ZLocations_t locs; 707 ZLocations_t locs;
629 int one = 1; 708 int one = 1;
630 GString *str = g_string_new(""); 709 GString *str = g_string_new("");
631 710
632 g_string_append_printf(str, _("<b>User:</b> %s<br>"), b ? b->name : user); 711 g_string_append_printf(str, _("<b>User:</b> %s<br>"), b ? b->name : user);
639 /* XXX add real error reporting */ 718 /* XXX add real error reporting */
640 ZGetLocations(&locs, &one); 719 ZGetLocations(&locs, &one);
641 g_string_append_printf(str, _("<br>At %s since %s"), locs.host, locs.time); 720 g_string_append_printf(str, _("<br>At %s since %s"), locs.host, locs.time);
642 } 721 }
643 gaim_notify_userinfo(gc, b ? b->name : user, NULL, _("Buddy Information"), NULL, 722 gaim_notify_userinfo(gc, b ? b->name : user, NULL, _("Buddy Information"), NULL,
644 str->str, NULL, NULL); 723 str->str, NULL, NULL);
645 g_string_free(str, TRUE); 724 g_string_free(str, TRUE);
646 } else 725 } else
647 serv_got_update(gc, b->name, nlocs, 0, 0, 0, 0); 726 serv_got_update(gc, b->name, nlocs, 0, 0, 0, 0);
648 727
649 g_free(user); 728 g_free(user);
653 char *send_inst; 732 char *send_inst;
654 GaimConversation *gconv1; 733 GaimConversation *gconv1;
655 GaimConvChat *gcc; 734 GaimConvChat *gcc;
656 char *ptr = notice.z_message + strlen(notice.z_message) + 1; 735 char *ptr = notice.z_message + strlen(notice.z_message) + 1;
657 int len; 736 int len;
658 char *sendertmp = g_strdup_printf("%s", gaim_zephyr_get_sender()); 737 char *sendertmp = g_strdup_printf("%s", zephyr->username);
659 int signature_length = strlen(notice.z_message); 738 int signature_length = strlen(notice.z_message);
660 int message_has_no_body = 0; 739 int message_has_no_body = 0;
661 GaimConvImFlags flags = 0; 740 GaimConvImFlags flags = 0;
662 gchar *tmpescape; 741 gchar *tmpescape;
663 742
664 /* Need to deal with 0 length messages to handle typing notification (OPCODE) ping messages */ 743 /* Need to deal with 0 length messages to handle typing notification (OPCODE) ping messages */
665 /* One field zephyrs would have caused gaim to crash */ 744 /* One field zephyrs would have caused gaim to crash */
666 if ( (notice.z_message_len == 0) || (signature_length >= notice.z_message_len - 1)) { 745 if ( (notice.z_message_len == 0) || (signature_length >= notice.z_message_len - 1)) {
667 message_has_no_body = 1; 746 message_has_no_body = 1;
681 buf3 = zephyr_recv_convert(gc,buf2, strlen(buf2)); 760 buf3 = zephyr_recv_convert(gc,buf2, strlen(buf2));
682 g_free(buf2); 761 g_free(buf2);
683 g_free(tmpescape); 762 g_free(tmpescape);
684 } 763 }
685 764
686 if (!g_ascii_strcasecmp(notice.z_class, "MESSAGE") && !g_ascii_strcasecmp(notice.z_class_inst, "PERSONAL") 765 if (!g_ascii_strcasecmp(notice.z_class, "MESSAGE") && !g_ascii_strcasecmp(notice.z_class_inst, "PERSONAL")
687 && !g_ascii_strcasecmp(notice.z_recipient,gaim_zephyr_get_sender())) { 766 && !g_ascii_strcasecmp(notice.z_recipient,zephyr->username)) {
688 gchar* stripped_sender; 767 gchar* stripped_sender;
689 if (!g_ascii_strcasecmp(notice.z_message, "Automated reply:")) 768 if (!g_ascii_strcasecmp(notice.z_message, "Automated reply:"))
690 flags |= GAIM_CONV_IM_AUTO_RESP; 769 flags |= GAIM_CONV_IM_AUTO_RESP;
691 stripped_sender = zephyr_strip_foreign_realm(notice.z_sender); 770 stripped_sender = zephyr_strip_foreign_realm(zephyr,notice.z_sender);
692 771
693 if (!g_ascii_strcasecmp(notice.z_opcode,"PING")) 772 if (!g_ascii_strcasecmp(notice.z_opcode,"PING"))
694 serv_got_typing(gc,stripped_sender,ZEPHYR_TYPING_RECV_TIMEOUT, GAIM_TYPING); 773 serv_got_typing(gc,stripped_sender,ZEPHYR_TYPING_RECV_TIMEOUT, GAIM_TYPING);
695 else 774 else {
696 serv_got_im(gc, stripped_sender, buf3, flags, time(NULL)); 775 /* Based on the values of
697 776 account->permit_deny,
698 g_free(stripped_sender); 777 account->permit, account>deny , and
778 the buddylist */
779
780 GSList* l;
781 gboolean in_deny;
782
783 switch (gc->account->perm_deny) {
784 case GAIM_PRIVACY_ALLOW_ALL:
785 in_deny = 0; break;
786 case GAIM_PRIVACY_DENY_ALL:
787 in_deny = 1; break;
788 case GAIM_PRIVACY_ALLOW_USERS: /* See if stripped_sender is in gc->account->permit and allow appropriately */
789 in_deny = 1;
790 for(l=gc->account->permit;l!=NULL;l=l->next) {
791 if (!gaim_utf8_strcasecmp(stripped_sender, gaim_normalize(gc->account, (char *)l->data))) {
792 in_deny=0;
793 break;
794 }
795 }
796 break;
797 case GAIM_PRIVACY_DENY_USERS: /* See if stripped_sender is in gc->account->deny and deny if so */
798 in_deny = 0;
799 for(l=gc->account->deny;l!=NULL;l=l->next) {
800 if (!gaim_utf8_strcasecmp(stripped_sender, gaim_normalize(gc->account, (char *)l->data))) {
801 in_deny=1;
802 break;
803 }
804 }
805 break;
806 case GAIM_PRIVACY_ALLOW_BUDDYLIST:
807 in_deny = 1;
808 if (gaim_find_buddy(gc->account,stripped_sender)!=NULL) {
809 in_deny = 0;
810 }
811 break;
812 default:
813 in_deny=0; break;
814 }
815
816 if (!in_deny) {
817 serv_got_im(gc, stripped_sender, buf3, flags, time(NULL));
818 }
819 }
820
821 g_free(stripped_sender);
822 } else {
823 zephyr_triple *zt1, *zt2;
824 gchar *send_inst_utf8;
825 zephyr_account *zephyr = gc->proto_data;
826 zt1 = new_triple(gc->proto_data,notice.z_class, notice.z_class_inst, notice.z_recipient);
827 zt2 = find_sub_by_triple(gc->proto_data,zt1);
828 if (!zt2) {
829 /* This is a server supplied subscription */
830 zephyr->subscrips = g_slist_append(zephyr->subscrips, new_triple(zephyr,zt1->class,zt1->instance,zt1->recipient));
831 zt2 = find_sub_by_triple(gc->proto_data,zt1);
832 }
833
834 if (!zt2->open) {
835 zt2->open = TRUE;
836 serv_got_joined_chat(gc, zt2->id, zt2->name);
837 zephyr_chat_set_topic(gc,zt2->id,notice.z_class_inst);
838 }
839 g_free(sendertmp); /* fix memory leak? */
840 /* If the person is in the default Realm, then strip the
841 Realm from the sender field */
842 sendertmp = zephyr_strip_foreign_realm(zephyr,notice.z_sender);
843 send_inst = g_strdup_printf("%s %s",sendertmp,notice.z_class_inst);
844 send_inst_utf8 = zephyr_recv_convert(gc,send_inst, strlen(send_inst));
845 if (!send_inst_utf8) {
846 gaim_debug(GAIM_DEBUG_ERROR, "zephyr","send_inst %s became null\n", send_inst);
847 send_inst_utf8 = "malformed instance";
848 }
849
850 serv_got_chat_in(gc, zt2->id, send_inst_utf8, 0, buf3, time(NULL));
851 g_free(send_inst);
852 gconv1 = gaim_find_conversation_with_account(zt2->name, gc->account);
853 gcc = gaim_conversation_get_chat_data(gconv1);
854
855 if (!gaim_conv_chat_find_user(gcc, sendertmp)) {
856 /* force interpretation in network byte order */
857 unsigned char *addrs = (unsigned char *)&(notice.z_sender_addr.s_addr);
858 gchar* ipaddr = g_strdup_printf("%hhd.%hhd.%hhd.%hhd", (unsigned char)addrs[0],
859 (unsigned char)addrs[1], (unsigned char)addrs[2],
860 (unsigned char) addrs[3]);
861
862 gaim_conv_chat_add_user(gcc, sendertmp, ipaddr, GAIM_CBFLAGS_NONE, TRUE);
863 g_free(ipaddr); /* fix memory leak? */
864
865 }
866 g_free(sendertmp);
867 g_free(send_inst_utf8);
868
869 free_triple(zt1);
870 }
871 g_free(buf3);
872
873 }
874 }
875 int free_parse_tree(parse_tree* tree) {
876 if (!tree) {
877 return 0;
878 }
879 else {
880 int i;
881 if (tree->children) {
882 for(i=0;i<tree->num_children;i++){
883 if (tree->children[i]) {
884 free_parse_tree(tree->children[i]);
885 g_free(tree->children[i]);
886 }
887 }
888 }
889 if ((tree != &null_parse_tree) && (tree->contents != NULL))
890 g_free(tree->contents);
891
892 }
893 return 0;
894 }
895
896 parse_tree *tree_child(parse_tree* tree,int index) {
897 if (index < tree->num_children) {
898 return tree->children[index];
899 } else {
900 return &null_parse_tree;
901 }
902 }
903
904 parse_tree *find_node(parse_tree* ptree,gchar* key)
905 {
906 gchar* tc = tree_child(ptree,0)->contents;
907
908 if (!ptree || ! key)
909 return &null_parse_tree;
910
911 if (ptree->num_children > 0 && tc && !strcasecmp(tc, key)) {
912 return ptree;
913 } else {
914 parse_tree *result = &null_parse_tree;
915 int i;
916 for(i = 0; i < ptree->num_children; i++) {
917 result = find_node(ptree->children[i],key);
918 if(result != &null_parse_tree) {
919 break;
920 }
921 }
922 return result;
923 }
924 }
925
926 parse_tree *parse_buffer(gchar* source, gboolean do_parse) {
927
928 parse_tree *ptree = g_new0(parse_tree,1);
929 ptree->contents = NULL;
930 ptree->num_children=0;
931 if (do_parse) {
932 unsigned int p = 0;
933 while(p < strlen(source)) {
934 unsigned int end;
935 gchar *newstr;
936
937 /* Eat white space: */
938 if(g_ascii_isspace(source[p]) || source[p] == '\001') {
939 p++;
940 continue;
941 }
942
943 /* Skip comments */
944 if(source[p] == ';') {
945 while(source[p] != '\n' && p < strlen(source)) {
946 p++;
947 }
948 continue;
949 }
950
951 if(source[p] == '(') {
952 int nesting = 0;
953 gboolean in_quote = FALSE;
954 gboolean escape_next = FALSE;
955 p++;
956 end = p;
957 while(!(source[end] == ')' && nesting == 0 && !in_quote) && end < strlen(source)) {
958 if(!escape_next) {
959 if(source[end] == '\\') {
960 escape_next = TRUE;
961 }
962 if(!in_quote) {
963 if(source[end] == '(') {
964 nesting++;
965 }
966 if(source[end] == ')') {
967 nesting--;
968 }
969 }
970 if(source[end] == '"') {
971 in_quote = !in_quote;
972 }
973 } else {
974 escape_next = FALSE;
975 }
976 end++;
977 }
978 do_parse = TRUE;
979
699 } else { 980 } else {
700 zephyr_triple *zt1, *zt2; 981 gchar end_char;
701 gchar *send_inst_utf8; 982 if(source[p] == '"') {
702 zephyr_account *zephyr = gc->proto_data; 983 end_char = '"';
703 zt1 = new_triple(gc->proto_data,notice.z_class, notice.z_class_inst, notice.z_recipient); 984 p++;
704 zt2 = find_sub_by_triple(gc->proto_data,zt1); 985 } else {
705 if (!zt2) { 986 end_char = ' ';
706 /* This is a server supplied subscription */ 987 }
707 zephyr->subscrips = g_slist_append(zephyr->subscrips, zt1); 988 do_parse = FALSE;
708 zt2 = find_sub_by_triple(gc->proto_data,zt1); 989
709 } 990 end = p;
710 991 while(source[end] != end_char && end < strlen(source)) {
711 if (!zt2->open) { 992 if(source[end] == '\\')
712 zt2->open = TRUE; 993 end++;
713 serv_got_joined_chat(gc, zt2->id, zt2->name); 994 end++;
714 zephyr_chat_set_topic(gc,zt2->id,notice.z_class_inst); 995 }
715 } 996 }
716 g_free(sendertmp); /* fix memory leak? */ 997 newstr = g_new0(gchar, end+1-p);
717 /* If the person is in the default Realm, then strip the 998 strncpy(newstr,source+p,end-p);
718 Realm from the sender field */ 999 if (ptree->num_children < MAXCHILDREN) {
719 sendertmp = zephyr_strip_foreign_realm(notice.z_sender); 1000 /* In case we surpass maxchildren, ignore this */
720 send_inst = g_strdup_printf("%s %s",sendertmp,notice.z_class_inst); 1001 ptree->children[ptree->num_children++] = parse_buffer( newstr, do_parse);
721 send_inst_utf8 = zephyr_recv_convert(gc,send_inst, strlen(send_inst)); 1002 } else {
722 if (!send_inst_utf8) { 1003 gaim_debug_error("zephyr","too many children in tzc output. skipping\n");
723 gaim_debug(GAIM_DEBUG_ERROR, "zephyr","send_inst %s became null\n", send_inst); 1004 }
724 send_inst_utf8 = "malformed instance"; 1005 g_free(newstr);
725 } 1006 p = end + 1;
726 1007 }
727 serv_got_chat_in(gc, zt2->id, send_inst_utf8, 0, buf3, time(NULL)); 1008 return ptree;
728 g_free(send_inst); 1009 } else {
729 gconv1 = gaim_find_conversation_with_account(zt2->name, gc->account); 1010 /* XXX does this have to be strdup'd */
730 gcc = gaim_conversation_get_chat_data(gconv1); 1011 ptree->contents = g_strdup(source);
731 1012 return ptree;
732 if (!gaim_conv_chat_find_user(gcc, sendertmp)) { 1013 }
733 /* force interpretation in network byte order */ 1014 }
734 unsigned char *addrs = (unsigned char *)&(notice.z_sender_addr.s_addr); 1015
735 gchar* ipaddr = g_strdup_printf("%hhd.%hhd.%hhd.%hhd", (unsigned char)addrs[0], 1016 parse_tree *read_from_tzc(zephyr_account* zephyr){
736 (unsigned char)addrs[1], (unsigned char)addrs[2], 1017 struct timeval tv;
737 (unsigned char) addrs[3]); 1018 fd_set rfds;
738 1019 int bufsize = 2048;
739 gaim_conv_chat_add_user(gcc, sendertmp, ipaddr, GAIM_CBFLAGS_NONE, TRUE); 1020 char *buf = (char *)calloc(bufsize, 1);
740 g_free(ipaddr); /* fix memory leak? */ 1021 char *bufcur = buf;
741 1022 int selected = 0;
742 } 1023 parse_tree *incoming_msg;
743 g_free(sendertmp); 1024
744 g_free(send_inst_utf8); 1025 FD_ZERO(&rfds);
745 1026 FD_SET(zephyr->fromtzc[ZEPHYR_FD_READ], &rfds);
746 free_triple(zt1); 1027 tv.tv_sec = 0;
747 } 1028 tv.tv_usec = 0;
748 g_free(buf3); 1029 incoming_msg=NULL;
749 1030
750 } 1031 while (select(zephyr->fromtzc[ZEPHYR_FD_READ] + 1, &rfds, NULL, NULL, &tv)) {
751 } 1032 selected = 1;
752 1033 read(zephyr->fromtzc[ZEPHYR_FD_READ], bufcur, 1);
753 static gint check_notify(gpointer data) 1034 bufcur++;
1035 if ((bufcur - buf) > (bufsize - 1)) {
1036 if ((buf = realloc(buf, bufsize * 2)) == NULL) {
1037 gaim_debug_error("zephyr","Ran out of memory");
1038 exit(-1);
1039 } else {
1040 bufcur = buf + bufsize;
1041 bufsize *= 2;
1042 }
1043 }
1044 }
1045 *bufcur = '\0';
1046
1047 if (selected) {
1048 incoming_msg = parse_buffer(buf,TRUE);
1049 }
1050 free(buf);
1051 return incoming_msg;
1052 }
1053
1054 static gint check_notify_tzc(gpointer data)
1055 {
1056 GaimConnection *gc = (GaimConnection *)data;
1057 zephyr_account* zephyr = gc->proto_data;
1058 parse_tree *newparsetree = read_from_tzc(zephyr);
1059 struct sockaddr_in from;
1060 if (newparsetree != NULL) {
1061 gchar *spewtype;
1062 if ( (spewtype = tree_child(find_node(newparsetree,"tzcspew"),2)->contents) ) {
1063 if (!g_ascii_strncasecmp(spewtype,"message",7)) {
1064 ZNotice_t notice;
1065 parse_tree *msgnode = tree_child(find_node(newparsetree,"message"),2);
1066 parse_tree *bodynode = tree_child(msgnode,1);
1067 /* char *zsig = g_strdup(" "); */ /* gaim doesn't care about zsigs */
1068 char *msg = zephyr_tzc_deescape_str(bodynode->contents);
1069 size_t bufsize = strlen(msg) + 3;
1070 char *buf = g_new0(char,bufsize);
1071 g_snprintf(buf,1+strlen(msg)+2," %c%s",'\0',msg);
1072 bzero((char *)&notice, sizeof(notice));
1073 notice.z_kind = ACKED;
1074 notice.z_port = 0;
1075 notice.z_opcode = tree_child(find_node(newparsetree,"opcode"),2)->contents;
1076 notice.z_class = zephyr_tzc_deescape_str(tree_child(find_node(newparsetree,"class"),2)->contents);
1077 notice.z_class_inst = tree_child(find_node(newparsetree,"instance"),2)->contents;
1078 notice.z_recipient = local_zephyr_normalize(zephyr,tree_child(find_node(newparsetree,"recipient"),2)->contents);
1079 notice.z_sender = local_zephyr_normalize(zephyr,tree_child(find_node(newparsetree,"sender"),2)->contents);
1080 notice.z_default_format = "Class $class, Instance $instance:\n" "To: @bold($recipient) at $time $date\n" "From: @bold($1) <$sender>\n\n$2";
1081 notice.z_message_len = strlen(msg) + 3;
1082 notice.z_message = buf;
1083 handle_message(gc,notice,from);
1084 g_free(msg);
1085 /* g_free(zsig); */
1086 g_free(buf);
1087 /* free_parse_tree(msgnode);
1088 free_parse_tree(bodynode);
1089 g_free(msg);
1090 g_free(zsig);
1091 g_free(buf);
1092 */
1093 }
1094 else if (!g_ascii_strncasecmp(spewtype,"zlocation",9)) {
1095 /* check_loc or zephyr_zloc respectively */
1096 /* XXX fix */
1097 char *user;
1098 GaimBuddy *b;
1099 int nlocs = 0;
1100 parse_tree *locations;
1101 gchar *locval;
1102 user = tree_child(find_node(newparsetree,"user"),2)->contents;
1103
1104 if ((b = gaim_find_buddy(gc->account, user)) == NULL) {
1105 char *e = strchr(user, '@');
1106
1107 if (e && !g_ascii_strcasecmp(e + 1, zephyr->realm)) {
1108 *e = '\0';
1109 }
1110 b = gaim_find_buddy(gc->account, user);
1111 }
1112
1113 locations = find_node(newparsetree,"locations");
1114 locval = tree_child(tree_child(tree_child(tree_child(locations,2),0),0),2)->contents;
1115 /* fprintf(stderr,"locval: %s %d\n",locval,strlen(locval)); */
1116
1117 if (!locval || !g_ascii_strcasecmp(locval," ") || (strlen(locval) == 0)) {
1118 nlocs = 0;
1119 } else {
1120 nlocs = 1;
1121 }
1122
1123 if ((b && pending_zloc(zephyr,b->name)) || pending_zloc(zephyr,user) || pending_zloc(zephyr,local_zephyr_normalize(zephyr,user))){
1124 GString *str = g_string_new("");
1125
1126 g_string_append_printf(str, _("<b>User:</b> %s<br>"), b ? b->name : user);
1127 if (b && b->alias)
1128 g_string_append_printf(str, _("<b>Alias:</b> %s<br>"), b->alias);
1129
1130 if (!nlocs) {
1131 g_string_append_printf(str, _("<br>Hidden or not logged-in"));
1132 } else {
1133 g_string_append_printf(str, _("<br>At %s since %s"),
1134 tree_child(tree_child(tree_child(tree_child(locations,2),0),0),2)->contents,
1135 tree_child(tree_child(tree_child(tree_child(locations,2),0),2),2)->contents);
1136 }
1137
1138 gaim_notify_userinfo(gc, b ? b->name : user, NULL, _("Buddy Information"), NULL,
1139 str->str, NULL, NULL);
1140 g_string_free(str, TRUE);
1141 } else {
1142 serv_got_update(gc, b->name, nlocs, 0, 0, 0, 0);
1143 }
1144 }
1145 else if (!g_ascii_strncasecmp(spewtype,"subscribed",10)) {
1146 }
1147 else if (!g_ascii_strncasecmp(spewtype,"start",5)) {
1148 }
1149 else if (!g_ascii_strncasecmp(spewtype,"error",5)) {
1150 /* XXX handle */
1151 }
1152 } else {
1153 }
1154 } else {
1155 }
1156
1157 free_parse_tree(newparsetree);
1158 return TRUE;
1159 }
1160
1161 static gint check_notify_zeph02(gpointer data)
754 { 1162 {
755 /* XXX add real error reporting */ 1163 /* XXX add real error reporting */
756 GaimConnection *gc = (GaimConnection*) data; 1164 GaimConnection *gc = (GaimConnection*) data;
757 while (ZPending()) { 1165 while (ZPending()) {
758 ZNotice_t notice; 1166 ZNotice_t notice;
759 struct sockaddr_in from; 1167 struct sockaddr_in from;
760 /* XXX add real error reporting */ 1168 /* XXX add real error reporting */
761 1169
789 1197
790 static gint check_loc(gpointer data) 1198 static gint check_loc(gpointer data)
791 { 1199 {
792 GaimBlistNode *gnode, *cnode, *bnode; 1200 GaimBlistNode *gnode, *cnode, *bnode;
793 ZAsyncLocateData_t ald; 1201 ZAsyncLocateData_t ald;
794 GaimConnection *gc = (GaimConnection*)data; 1202 GaimConnection *gc = (GaimConnection *)data;
795 1203 zephyr_account *zephyr = gc->proto_data;
796 ald.user = NULL; 1204
797 memset(&(ald.uid), 0, sizeof(ZUnique_Id_t)); 1205 if (use_zeph02(zephyr)) {
798 ald.version = NULL; 1206 ald.user = NULL;
1207 memset(&(ald.uid), 0, sizeof(ZUnique_Id_t));
1208 ald.version = NULL;
1209 }
799 1210
800 for (gnode = gaim_get_blist()->root; gnode; gnode = gnode->next) { 1211 for (gnode = gaim_get_blist()->root; gnode; gnode = gnode->next) {
801 if (!GAIM_BLIST_NODE_IS_GROUP(gnode)) 1212 if (!GAIM_BLIST_NODE_IS_GROUP(gnode))
802 continue; 1213 continue;
803 for (cnode = gnode->child; cnode; cnode = cnode->next) { 1214 for (cnode = gnode->child; cnode; cnode = cnode->next) {
809 if (!GAIM_BLIST_NODE_IS_BUDDY(bnode)) 1220 if (!GAIM_BLIST_NODE_IS_BUDDY(bnode))
810 continue; 1221 continue;
811 if (b->account->gc == gc) { 1222 if (b->account->gc == gc) {
812 const char *chk; 1223 const char *chk;
813 1224
814 chk = local_zephyr_normalize(b->name); 1225 chk = local_zephyr_normalize(zephyr,b->name);
1226 gaim_debug_info("zephyr","chk: %s b->name %s\n",chk,b->name);
815 /* XXX add real error reporting */ 1227 /* XXX add real error reporting */
816 /* doesn't matter if this fails or not; we'll just move on to the next one */ 1228 /* doesn't matter if this fails or not; we'll just move on to the next one */
817 ZRequestLocations(chk, &ald, UNACKED, ZAUTH); 1229 if (use_zeph02(zephyr)) {
818 g_free(ald.user); 1230 #ifdef WIN32
819 g_free(ald.version); 1231 int numlocs;
820 } 1232 int one=1;
821 } 1233 ZLocateUser(chk,&numlocs,ZAUTH);
822 } 1234 if (numlocs) {
823 } 1235 int i;
824 1236 for(i=0;i<numlocs;i++) {
1237 ZGetLocations(&locations,&one);
1238 serv_got_update(gc,b->name,1,0,0,0,0);
1239 }
1240 }
1241 #else
1242 ZRequestLocations(chk, &ald, UNACKED, ZAUTH);
1243 g_free(ald.user);
1244 g_free(ald.version);
1245 #endif /* WIN32 */
1246 } else
1247 if (use_tzc(zephyr)) {
1248 gchar *zlocstr = g_strdup_printf("((tzcfodder . zlocate) \"%s\")\n",chk);
1249 write(zephyr->totzc[ZEPHYR_FD_WRITE],zlocstr,strlen(zlocstr));
1250 g_free(zlocstr);
1251 }
1252 }
1253 }
1254 }
1255 }
1256
825 return TRUE; 1257 return TRUE;
826 } 1258 }
827 1259
828 static char *get_exposure_level() 1260 static char *get_exposure_level()
829 { 1261 {
853 *tmp = '\0'; 1285 *tmp = '\0';
854 g_strchug(str); 1286 g_strchug(str);
855 g_strchomp(str); 1287 g_strchomp(str);
856 } 1288 }
857 1289
858 static void zephyr_inithosts(zephyr_account* zephyr) 1290 static void zephyr_inithosts(zephyr_account *zephyr)
859 { 1291 {
860 /* XXX This code may not be Win32 clean */ 1292 /* XXX This code may not be Win32 clean */
861 struct hostent *hent; 1293 struct hostent *hent;
862 1294
863 if (gethostname(zephyr->ourhost, sizeof(zephyr->ourhost)) == -1) { 1295 if (gethostname(zephyr->ourhost, sizeof(zephyr->ourhost)) == -1) {
888 1320
889 FILE *f; 1321 FILE *f;
890 gchar *fname; 1322 gchar *fname;
891 gchar buff[BUFSIZ]; 1323 gchar buff[BUFSIZ];
892 1324
893 zephyr_inithosts(zephyr);
894 fname = g_strdup_printf("%s/.zephyr.subs", gaim_home_dir()); 1325 fname = g_strdup_printf("%s/.zephyr.subs", gaim_home_dir());
895 f = fopen(fname, "r"); 1326 f = fopen(fname, "r");
896 if (f) { 1327 if (f) {
897 char **triple; 1328 char **triple;
898 ZSubscription_t sub;
899 char *recip; 1329 char *recip;
900 char *z_class; 1330 char *z_class;
901 char *z_instance; 1331 char *z_instance;
1332 char *z_galaxy = NULL;
902 1333
903 while (fgets(buff, BUFSIZ, f)) { 1334 while (fgets(buff, BUFSIZ, f)) {
904 strip_comments(buff); 1335 strip_comments(buff);
905 if (buff[0]) { 1336 if (buff[0]) {
906 triple = g_strsplit(buff, ",", 3); 1337 triple = g_strsplit(buff, ",", 3);
907 if (triple[0] && triple[1]) { 1338 if (triple[0] && triple[1]) {
908 char *tmp = g_strdup_printf("%s", gaim_zephyr_get_sender()); 1339 char *tmp = g_strdup_printf("%s", zephyr->username);
909 char *atptr; 1340 char *atptr;
910 1341
911 sub.zsub_class = triple[0]; 1342 z_class = triple[0];
912 sub.zsub_classinst = triple[1]; 1343 z_instance = triple[1];
913 if (triple[2] == NULL) { 1344 if (triple[2] == NULL) {
914 recip = g_malloc0(1); 1345 recip = g_malloc0(1);
915 } else if (!g_ascii_strcasecmp(triple[2], "%me%")) { 1346 } else if (!g_ascii_strcasecmp(triple[2], "%me%")) {
916 recip = g_strdup_printf("%s", gaim_zephyr_get_sender()); 1347 recip = g_strdup_printf("%s", zephyr->username);
917 } else if (!g_ascii_strcasecmp(triple[2], "*")) { 1348 } else if (!g_ascii_strcasecmp(triple[2], "*")) {
918 /* wildcard 1349 /* wildcard
919 * form of class,instance,* */ 1350 * form of class,instance,* */
920 recip = g_malloc0(1); 1351 recip = g_malloc0(1);
921 } else if (!g_ascii_strcasecmp(triple[2], tmp)) { 1352 } else if (!g_ascii_strcasecmp(triple[2], tmp)) {
925 /* form of class,instance,*@ANDREW.CMU.EDU 1356 /* form of class,instance,*@ANDREW.CMU.EDU
926 * class,instance,@ANDREW.CMU.EDU 1357 * class,instance,@ANDREW.CMU.EDU
927 * If realm is local realm, blank recipient, else 1358 * If realm is local realm, blank recipient, else
928 * @REALM-NAME 1359 * @REALM-NAME
929 */ 1360 */
930 char *realmat = g_strdup_printf("@%s", 1361 char *realmat = g_strdup_printf("@%s",zephyr->realm);
931 gaim_zephyr_get_realm());
932 1362
933 if (!g_ascii_strcasecmp(atptr, realmat)) 1363 if (!g_ascii_strcasecmp(atptr, realmat))
934 recip = g_malloc0(1); 1364 recip = g_malloc0(1);
935 else 1365 else
936 recip = g_strdup(atptr); 1366 recip = g_strdup(atptr);
937 g_free(realmat); 1367 g_free(realmat);
938 } else { 1368 } else {
939 recip = g_strdup(triple[2]); 1369 recip = g_strdup(triple[2]);
940 } 1370 }
941 g_free(tmp); 1371 g_free(tmp);
942 sub.zsub_recipient = recip;
943 1372
944 if (!g_ascii_strcasecmp(triple[0],"%host%")) { 1373 if (!g_ascii_strcasecmp(triple[0],"%host%")) {
945 z_class = g_strdup(zephyr->ourhost); 1374 z_class = g_strdup(zephyr->ourhost);
946 } else if (!g_ascii_strcasecmp(triple[0],"%canon%")) { 1375 } else if (!g_ascii_strcasecmp(triple[0],"%canon%")) {
947 z_class = g_strdup(zephyr->ourhostcanon); 1376 z_class = g_strdup(zephyr->ourhostcanon);
948 } else { 1377 } else {
949 z_class = g_strdup(triple[0]); 1378 z_class = g_strdup(triple[0]);
950 } 1379 }
951 sub.zsub_class = z_class;
952 1380
953 if (!g_ascii_strcasecmp(triple[1],"%host%")) { 1381 if (!g_ascii_strcasecmp(triple[1],"%host%")) {
954 z_instance = g_strdup(zephyr->ourhost); 1382 z_instance = g_strdup(zephyr->ourhost);
955 } else if (!g_ascii_strcasecmp(triple[1],"%canon%")) { 1383 } else if (!g_ascii_strcasecmp(triple[1],"%canon%")) {
956 z_instance = g_strdup(zephyr->ourhostcanon); 1384 z_instance = g_strdup(zephyr->ourhostcanon);
957 } else { 1385 } else {
958 z_instance = g_strdup(triple[1]); 1386 z_instance = g_strdup(triple[1]);
959 } 1387 }
960 sub.zsub_classinst = z_instance;
961 1388
962 /* There should be some sort of error report listing classes that couldn't be subbed to. 1389 /* There should be some sort of error report listing classes that couldn't be subbed to.
963 Not important right now though */ 1390 Not important right now though */
964 1391
965 if (ZSubscribeTo(&sub, 1, 0) != ZERR_NONE) { 1392 if (zephyr_subscribe_to(zephyr,z_class, z_instance, recip,z_galaxy) != ZERR_NONE) {
966 1393
967 gaim_debug(GAIM_DEBUG_ERROR, "zephyr", "Couldn't subscribe to %s, %s, %s\n", sub.zsub_class, sub.zsub_classinst, sub.zsub_recipient); 1394 gaim_debug(GAIM_DEBUG_ERROR, "zephyr", "Couldn't subscribe to %s, %s, %s\n", z_class,z_instance,recip);
968 } 1395 }
969 1396
970 zephyr->subscrips = g_slist_append(zephyr->subscrips, new_triple(zephyr,sub.zsub_class,sub.zsub_classinst,sub.zsub_recipient)); 1397 zephyr->subscrips = g_slist_append(zephyr->subscrips, new_triple(zephyr,z_class,z_instance,recip));
971 /* g_hash_table_destroy(sub_hash_table); */ 1398 /* g_hash_table_destroy(sub_hash_table); */
972 g_free(z_instance); 1399 g_free(z_instance);
973 g_free(z_class); 1400 g_free(z_class);
974 g_free(recip); 1401 g_free(recip);
975 } 1402 }
1007 g_free(filename); 1434 g_free(filename);
1008 } 1435 }
1009 1436
1010 static void zephyr_login(GaimAccount * account) 1437 static void zephyr_login(GaimAccount * account)
1011 { 1438 {
1012 ZSubscription_t sub; 1439 GaimConnection *gc;
1013 GaimConnection *gc; 1440 zephyr_account *zephyr;
1014 zephyr_account *zephyr;
1015 1441
1016 gc = gaim_account_get_connection(account); 1442 gc = gaim_account_get_connection(account);
1017 gc->flags |= GAIM_CONNECTION_HTML | GAIM_CONNECTION_NO_BGCOLOR | GAIM_CONNECTION_NO_URLDESC; 1443 gc->flags |= GAIM_CONNECTION_HTML | GAIM_CONNECTION_NO_BGCOLOR | GAIM_CONNECTION_NO_URLDESC;
1018 gc->proto_data = zephyr=g_new0(zephyr_account,1); 1444 gc->proto_data = zephyr=g_new0(zephyr_account,1);
1019 1445 zephyr->account = account;
1446 zephyr->exposure = g_strdup(gaim_account_get_string(gc->account, "exposure_level", EXPOSE_REALMVIS));
1447
1448 if (gaim_account_get_bool(gc->account,"use_tzc",0)) {
1449 zephyr->connection_type = GAIM_ZEPHYR_TZC;
1450 } else {
1451 zephyr->connection_type = GAIM_ZEPHYR_KRB4;
1452 }
1453
1454 zephyr->encoding = (char *)gaim_account_get_string(gc->account, "encoding", ZEPHYR_FALLBACK_CHARSET);
1020 gaim_connection_update_progress(gc, _("Connecting"), 0, 8); 1455 gaim_connection_update_progress(gc, _("Connecting"), 0, 8);
1021 1456
1022 /* XXX z_call_s should actually try to report the com_err determined error */ 1457 /* XXX z_call_s should actually try to report the com_err determined error */
1023 1458 if (use_tzc(zephyr)) {
1024 z_call_s(ZInitialize(), "Couldn't initialize zephyr"); 1459 pid_t pid;
1025 z_call_s(ZOpenPort(&(zephyr->port)), "Couldn't open port"); 1460 /* gaim_connection_error(gc,"tzc not supported yet"); */
1026 z_call_s(ZSetLocation((char *) 1461 if ((pipe(zephyr->totzc) != 0) || (pipe(zephyr->fromtzc) != 0)) {
1027 gaim_account_get_string(gc->account, "exposure_level", EXPOSE_REALMVIS)), "Couldn't set location"); 1462 gaim_debug_error("zephyr", "pipe creation failed. killing\n");
1028 1463 exit(-1);
1029 sub.zsub_class = "MESSAGE"; 1464 }
1030 sub.zsub_classinst = "PERSONAL"; 1465
1031 sub.zsub_recipient = (char *)gaim_zephyr_get_sender(); 1466 pid = fork();
1032 1467
1033 if (ZSubscribeTo(&sub, 1, 0) != ZERR_NONE) { 1468 if (pid == -1) {
1469 gaim_debug_error("zephyr", "forking failed\n");
1470 exit(-1);
1471 }
1472 if (pid == 0) {
1473 unsigned int i=0;
1474 gboolean found_ps = FALSE;
1475 gchar ** tzc_cmd_array = g_strsplit(gaim_account_get_string(gc->account,"tzc_command","/usr/bin/tzc -e %s")," ",0);
1476 if (close(1) == -1) {
1477 gaim_debug_error("zephyr", "stdout couldn't be closed. dying\n");
1478 exit(-1);
1479 }
1480 if (dup2(zephyr->fromtzc[1], 1) == -1) {
1481 gaim_debug_error("zephyr", "dup2 of stdout failed \n");
1482 exit(-1);
1483 }
1484 if (close(zephyr->fromtzc[1]) == -1) {
1485 gaim_debug_error("zephyr", "closing of piped stdout failed\n");
1486 exit(-1);
1487 }
1488 if (close(0) == -1) {
1489 gaim_debug_error("zephyr", "stdin couldn't be closed. dying\n");
1490 exit(-1);
1491 }
1492 if (dup2(zephyr->totzc[0], 0) == -1) {
1493 gaim_debug_error("zephyr", "dup2 of stdin failed \n");
1494 exit(-1);
1495 }
1496 if (close(zephyr->totzc[0]) == -1) {
1497 gaim_debug_error("zephyr", "closing of piped stdin failed\n");
1498 exit(-1);
1499 }
1500 /* tzc_command should really be of the form
1501 path/to/tzc -e %s
1502 or
1503 ssh username@hostname pathtotzc -e %s
1504 -- this should not require a password, and ideally should be kerberized ssh --
1505 or
1506 fsh username@hostname pathtotzc -e %s
1507 */
1508 while(tzc_cmd_array[i] != NULL){
1509 if (!g_strncasecmp(tzc_cmd_array[i],"%s",2)) {
1510 /* fprintf(stderr,"replacing %%s with %s\n",zephyr->exposure); */
1511 tzc_cmd_array[i] = g_strdup(zephyr->exposure);
1512 found_ps = TRUE;
1513
1514 } else {
1515 /* fprintf(stderr,"keeping %s\n",tzc_cmd_array[i]); */
1516 }
1517 i++;
1518 }
1519
1520 if (!found_ps) {
1521 gaim_connection_error(gc,"Tzc command needs %s to set the exposure\n");
1522 return;
1523 }
1524
1525 execvp(tzc_cmd_array[0], tzc_cmd_array);
1526 }
1527 else {
1528 fd_set rfds;
1529 int bufsize = 2048;
1530 char *buf = (char *)calloc(bufsize, 1);
1531 char *bufcur = buf;
1532 struct timeval tv;
1533 char *ptr;
1534 int parenlevel=0;
1535 char* tempstr;
1536 int tempstridx;
1537
1538 zephyr->tzc_pid = pid;
1539 /* wait till we have data to read from ssh */
1540 FD_ZERO(&rfds);
1541 FD_SET(zephyr->fromtzc[ZEPHYR_FD_READ], &rfds);
1542
1543 tv.tv_sec = 10;
1544 tv.tv_usec = 0;
1545
1546 gaim_debug_info("zephyr", "about to read from tzc\n");
1547
1548 select(zephyr->fromtzc[ZEPHYR_FD_READ] + 1, &rfds, NULL, NULL, NULL);
1549
1550 FD_ZERO(&rfds);
1551 FD_SET(zephyr->fromtzc[ZEPHYR_FD_READ], &rfds);
1552 while (select(zephyr->fromtzc[ZEPHYR_FD_READ] + 1, &rfds, NULL, NULL, &tv)) {
1553 read(zephyr->fromtzc[ZEPHYR_FD_READ], bufcur, 1);
1554 bufcur++;
1555 if ((bufcur - buf) > (bufsize - 1)) {
1556 if ((buf = realloc(buf, bufsize * 2)) == NULL) {
1557 exit(-1);
1558 } else {
1559 bufcur = buf + bufsize;
1560 bufsize *= 2;
1561 }
1562 }
1563 FD_ZERO(&rfds);
1564 FD_SET(zephyr->fromtzc[ZEPHYR_FD_READ], &rfds);
1565 tv.tv_sec = 10;
1566 tv.tv_usec = 0;
1567
1568 }
1569 /* fprintf(stderr, "read from tzc\n"); */
1570 *bufcur = '\0';
1571 ptr = buf;
1572
1573 /* ignore all tzcoutput till we've received the first (*/
1574 while (ptr < bufcur && (*ptr !='(')) {
1575 ptr++;
1576 }
1577 if (ptr >=bufcur) {
1578 gaim_connection_error(gc,"invalid output by tzc (or bad parsing code)");
1579 return;
1580 }
1581
1582 while(ptr < bufcur) {
1583 if (*ptr == '(') {
1584 parenlevel++;
1585 }
1586 else if (*ptr == ')') {
1587 parenlevel--;
1588 }
1589 gaim_debug_info("zephyr","tzc parenlevel is %d\n",parenlevel);
1590 switch (parenlevel) {
1591 case 0:
1592 break;
1593 case 1:
1594 /* Search for next beginning (, or for the ending */
1595 ptr++;
1596 while((*ptr != '(') && (*ptr != ')') && (ptr <bufcur))
1597 ptr++;
1598 if (ptr >= bufcur)
1599 gaim_debug_error("zephyr","tzc parsing error\n");
1600 break;
1601 case 2:
1602 /* You are probably at
1603 (foo . bar ) or (foo . "bar") or (foo . chars) or (foo . numbers) or (foo . () )
1604 Parse all the data between the first and last f, and move past )
1605 */
1606 tempstr = g_malloc0(20000);
1607 tempstridx=0;
1608 while(parenlevel >1) {
1609 ptr++;
1610 if (*ptr == '(')
1611 parenlevel++;
1612 if (*ptr == ')')
1613 parenlevel--;
1614 if (parenlevel > 1) {
1615 tempstr[tempstridx++]=*ptr;
1616 } else {
1617 ptr++;
1618 }
1619 }
1620 gaim_debug_info("zephyr","tempstr parsed\n");
1621 /* tempstr should now be a tempstridx length string containing all characters
1622 from that after the first ( to the one before the last paren ). */
1623 /* We should have the following possible lisp strings but we don't care
1624 (tzcspew . start) (version . "something") (pid . number)*/
1625 /* We care about 'zephyrid . "username@REALM.NAME"' and 'exposure . "SOMETHING"' */
1626 tempstridx=0;
1627 if (!g_ascii_strncasecmp(tempstr,"zephyrid",8)) {
1628 gchar* username = g_malloc0(100);
1629 int username_idx=0;
1630 char *realm;
1631 gaim_debug_info("zephyr","zephyrid found\n");
1632 tempstridx+=8;
1633 while(tempstr[tempstridx] !='"' && tempstridx < 20000)
1634 tempstridx++;
1635 tempstridx++;
1636 while(tempstr[tempstridx] !='"' && tempstridx < 20000)
1637 username[username_idx++]=tempstr[tempstridx++];
1638
1639 zephyr->username = g_strdup_printf("%s",username);
1640 if ((realm = strchr(username,'@')))
1641 zephyr->realm = g_strdup_printf("%s",realm+1);
1642 else
1643 zephyr->realm = g_strdup("local-realm");
1644
1645 g_free(username);
1646 } else {
1647 gaim_debug_info("zephyr", "something that's not zephyr id found %s\n",tempstr);
1648 }
1649
1650 /* We don't care about anything else yet */
1651 g_free(tempstr);
1652 break;
1653 default:
1654 gaim_debug_info("zephyr","parenlevel is not 1 or 2\n");
1655 /* This shouldn't be happening */
1656 break;
1657 }
1658 if (parenlevel==0)
1659 break;
1660 } /* while (ptr < bufcur) { */
1661 gaim_debug_info("zephyr", "tzc startup done\n");
1662 }
1663 }
1664 else if ( use_zeph02(zephyr)) {
1665 z_call_s(ZInitialize(), "Couldn't initialize zephyr");
1666 z_call_s(ZOpenPort(&(zephyr->port)), "Couldn't open port");
1667 z_call_s(ZSetLocation((char *)zephyr->exposure), "Couldn't set location");
1668
1669 zephyr->username = g_strdup(ZGetSender());
1670 zephyr->realm = g_strdup(ZGetRealm());
1671 gaim_debug_info("zephyr","realm: %s\n",zephyr->realm);
1672 }
1673 else {
1674 gaim_connection_error(gc,"Only ZEPH0.2 supported currently");
1675 return;
1676 }
1677 gaim_debug_info("zephyr","does it get here\n");
1678 gaim_debug_info("zephyr"," realm: %s username:%s\n", zephyr->realm, zephyr->username);
1679
1680 /* For now */
1681 zephyr->galaxy = NULL;
1682 zephyr->krbtkfile = NULL;
1683 zephyr_inithosts(zephyr);
1684
1685 if (zephyr_subscribe_to(zephyr,"MESSAGE","PERSONAL",zephyr->username,NULL) != ZERR_NONE) {
1034 /* XXX don't translate this yet. It could be written better */ 1686 /* XXX don't translate this yet. It could be written better */
1035 /* XXX error messages could be handled with more detail */ 1687 /* XXX error messages could be handled with more detail */
1036 gaim_notify_error(account->gc, NULL, 1688 gaim_notify_error(account->gc, NULL,
1037 "Unable to subscribe to messages", "Unable to subscribe to initial messages"); 1689 "Unable to subscribe to messages", "Unable to subscribe to initial messages");
1038 return; 1690 return;
1039 } 1691 }
1040 1692
1041 gaim_connection_set_state(gc, GAIM_CONNECTED); 1693 gaim_connection_set_state(gc, GAIM_CONNECTED);
1694 process_anyone(gc);
1695 process_zsubs(zephyr);
1042 serv_finish_login(gc); 1696 serv_finish_login(gc);
1043 1697
1044 process_anyone(gc); 1698 if (use_zeph02(zephyr)) {
1045 process_zsubs(gc->proto_data); 1699 zephyr->nottimer = gaim_timeout_add(100, check_notify_zeph02, gc);
1046 1700 } else if (use_tzc(zephyr)) {
1047 zephyr->nottimer = gaim_timeout_add(100, check_notify, gc); 1701 zephyr->nottimer = gaim_timeout_add(100, check_notify_tzc, gc);
1048 zephyr->loctimer = gaim_timeout_add(20000, check_loc, gc); 1702 }
1703 zephyr->loctimer = gaim_timeout_add(20000, check_loc, gc);
1704
1049 } 1705 }
1050 1706
1051 static void write_zsubs(zephyr_account *zephyr) 1707 static void write_zsubs(zephyr_account *zephyr)
1052 { 1708 {
1053 /* Exports subscription (chat) list back to 1709 /* Exports subscription (chat) list back to
1054 * .zephyr.subs 1710 * .zephyr.subs
1055 * XXX deal with %host%, %canon%, unsubscriptions, and negative subscriptions (punts?) 1711 * XXX deal with %host%, %canon%, unsubscriptions, and negative subscriptions (punts?)
1056 */ 1712 */
1057 1713
1058 GSList *s = zephyr->subscrips; 1714 GSList *s = zephyr->subscrips;
1059 zephyr_triple *zt; 1715 zephyr_triple *zt;
1060 FILE *fd; 1716 FILE *fd;
1061 char *fname; 1717 char *fname;
1087 /* deal with instances */ 1743 /* deal with instances */
1088 1744
1089 if (!g_ascii_strcasecmp(triple[1],zephyr->ourhost)) { 1745 if (!g_ascii_strcasecmp(triple[1],zephyr->ourhost)) {
1090 zinst = g_strdup("%host%"); 1746 zinst = g_strdup("%host%");
1091 } else if (!g_ascii_strcasecmp(triple[1],zephyr->ourhostcanon)) { 1747 } else if (!g_ascii_strcasecmp(triple[1],zephyr->ourhostcanon)) {
1092 zinst = g_strdup("%canon%"); 1748 zinst = g_strdup("%canon%");;
1093 } else { 1749 } else {
1094 zinst = g_strdup(triple[1]); 1750 zinst = g_strdup(triple[1]);
1095 } 1751 }
1096 1752
1097 /* deal with recipients */ 1753 /* deal with recipients */
1098 if (triple[2] == NULL) { 1754 if (triple[2] == NULL) {
1099 zrecip = g_strdup("*"); 1755 zrecip = g_strdup("*");
1100 } else if (!g_ascii_strcasecmp(triple[2],"")){ 1756 } else if (!g_ascii_strcasecmp(triple[2],"")){
1101 zrecip = g_strdup("*"); 1757 zrecip = g_strdup("*");
1102 } else if (!g_ascii_strcasecmp(triple[2], gaim_zephyr_get_sender())) { 1758 } else if (!g_ascii_strcasecmp(triple[2], zephyr->username)) {
1103 zrecip = g_strdup("%me%"); 1759 zrecip = g_strdup("%me%");
1104 } else { 1760 } else {
1105 zrecip = g_strdup(triple[2]); 1761 zrecip = g_strdup(triple[2]);
1106 } 1762 }
1107 1763
1121 { 1777 {
1122 GaimBlistNode *gnode, *cnode, *bnode; 1778 GaimBlistNode *gnode, *cnode, *bnode;
1123 GaimBuddy *b; 1779 GaimBuddy *b;
1124 char *ptr, *fname, *ptr2; 1780 char *ptr, *fname, *ptr2;
1125 FILE *fd; 1781 FILE *fd;
1126 1782 zephyr_account* zephyr = gc->proto_data;
1127 fname = g_strdup_printf("%s/.anyone", gaim_home_dir()); 1783 fname = g_strdup_printf("%s/.anyone", gaim_home_dir());
1128 fd = fopen(fname, "w"); 1784 fd = fopen(fname, "w");
1129 if (!fd) { 1785 if (!fd) {
1130 g_free(fname); 1786 g_free(fname);
1131 return; 1787 return;
1144 if (b->account == gc->account) { 1800 if (b->account == gc->account) {
1145 if ((ptr = strchr(b->name, '@')) != NULL) { 1801 if ((ptr = strchr(b->name, '@')) != NULL) {
1146 ptr2 = ptr + 1; 1802 ptr2 = ptr + 1;
1147 /* We should only strip the realm name if the principal 1803 /* We should only strip the realm name if the principal
1148 is in the user's realm 1804 is in the user's realm
1149 */ 1805 */
1150 if (!g_ascii_strcasecmp(ptr2, gaim_zephyr_get_realm())) { 1806 if (!g_ascii_strcasecmp(ptr2, zephyr->realm)) {
1151 *ptr = '\0'; 1807 *ptr = '\0';
1152 } 1808 }
1153 } 1809 }
1154 fprintf(fd, "%s\n", b->name); 1810 fprintf(fd, "%s\n", b->name);
1155 if (ptr) 1811 if (ptr)
1165 1821
1166 static void zephyr_close(GaimConnection * gc) 1822 static void zephyr_close(GaimConnection * gc)
1167 { 1823 {
1168 GList *l; 1824 GList *l;
1169 GSList *s; 1825 GSList *s;
1170 zephyr_account *zephyr = gc->proto_data; 1826 zephyr_account *zephyr = gc->proto_data;
1827 pid_t tzc_pid = zephyr->tzc_pid;
1171 1828
1172 l = zephyr->pending_zloc_names; 1829 l = zephyr->pending_zloc_names;
1173 while (l) { 1830 while (l) {
1174 g_free((char *)l->data); 1831 g_free((char *)l->data);
1175 l = l->next; 1832 l = l->next;
1194 zephyr->nottimer = 0; 1851 zephyr->nottimer = 0;
1195 if (zephyr->loctimer) 1852 if (zephyr->loctimer)
1196 gaim_timeout_remove(zephyr->loctimer); 1853 gaim_timeout_remove(zephyr->loctimer);
1197 zephyr->loctimer = 0; 1854 zephyr->loctimer = 0;
1198 gc = NULL; 1855 gc = NULL;
1199 z_call(ZCancelSubscriptions(0)); 1856 if (use_zeph02(zephyr)) {
1200 z_call(ZUnsetLocation()); 1857 z_call(ZCancelSubscriptions(0));
1201 z_call(ZClosePort()); 1858 z_call(ZUnsetLocation());
1202 } 1859 z_call(ZClosePort());
1203 1860 } else {
1204 static int zephyr_send_message(char* zclass, char* instance, char* recipient, const char *im, 1861 /* assume tzc */
1862 if (kill(tzc_pid,SIGTERM) == -1) {
1863 int err=errno;
1864 if (err==EINVAL) {
1865 gaim_debug_error("zephyr","An invalid signal was specified when killing tzc\n");
1866 }
1867 else if (err==ESRCH) {
1868 gaim_debug_error("zephyr","Tzc's pid didn't exist while killing tzc\n");
1869 }
1870 else if (err==EPERM) {
1871 gaim_debug_error("zephyr","gaim didn't have permission to kill tzc\n");
1872 }
1873 else {
1874 gaim_debug_error("zephyr","miscellaneous error while attempting to close tzc\n");
1875 }
1876 }
1877 }
1878 }
1879
1880 static int zephyr_send_message(zephyr_account *zephyr,char* zclass, char* instance, char* recipient, const char *im,
1205 const char *sig, char *opcode) ; 1881 const char *sig, char *opcode) ;
1206 1882
1207 const char * zephyr_get_signature() 1883 const char * zephyr_get_signature()
1208 { 1884 {
1209 /* XXX add zephyr error reporting */ 1885 /* XXX add zephyr error reporting */
1210 const char * sig =ZGetVariable("zwrite-signature"); 1886 const char * sig =ZGetVariable("zwrite-signature");
1211 if (!sig) { 1887 if (!sig) {
1212 sig = g_get_real_name(); 1888 sig = g_get_real_name();
1213 } 1889 }
1214 return sig; 1890 return sig;
1215 } 1891 }
1216 1892
1217 static int zephyr_chat_send(GaimConnection * gc, int id, const char *im) 1893 static int zephyr_chat_send(GaimConnection * gc, int id, const char *im)
1218 { 1894 {
1219 zephyr_triple *zt; 1895 zephyr_triple *zt;
1220 const char *sig; 1896 const char *sig;
1221 GaimConversation *gconv1; 1897 GaimConversation *gconv1;
1222 GaimConvChat *gcc; 1898 GaimConvChat *gcc;
1223 char *inst; 1899 char *inst;
1224 char *recipient; 1900 char *recipient;
1901 zephyr_account *zephyr = gc->proto_data;
1225 1902
1226 zt = find_sub_by_id(gc->proto_data,id); 1903 zt = find_sub_by_id(gc->proto_data,id);
1227 if (!zt) 1904 if (!zt)
1228 /* this should never happen. */ 1905 /* this should never happen. */
1229 return -EINVAL; 1906 return -EINVAL;
1230 1907
1231 sig = zephyr_get_signature(); 1908 sig = zephyr_get_signature();
1232 1909
1233 gconv1 = gaim_find_conversation_with_account(zt->name, gc->account); 1910 gconv1 = gaim_find_conversation_with_account(zt->name, gc->account);
1234 gcc = gaim_conversation_get_chat_data(gconv1); 1911 gcc = gaim_conversation_get_chat_data(gconv1);
1235 1912
1236 if (!(inst = (char *)gaim_conv_chat_get_topic(gcc))) 1913 if (!(inst = (char *)gaim_conv_chat_get_topic(gcc)))
1237 inst = g_strdup("PERSONAL"); 1914 inst = g_strdup("PERSONAL");
1238 1915
1239 if (!g_ascii_strcasecmp(zt->recipient, "*")) 1916 if (!g_ascii_strcasecmp(zt->recipient, "*"))
1240 recipient = local_zephyr_normalize(""); 1917 recipient = local_zephyr_normalize(zephyr,"");
1241 else 1918 else
1242 recipient = local_zephyr_normalize(zt->recipient); 1919 recipient = local_zephyr_normalize(zephyr,zt->recipient);
1243 1920
1244 zephyr_send_message(zt->class,inst,recipient,im,sig,""); 1921 zephyr_send_message(zephyr,zt->class,inst,recipient,im,sig,"");
1245 /* g_free(inst); */
1246 /* g_free(recipient); */
1247 return 0; 1922 return 0;
1248 } 1923 }
1249 1924
1250 1925
1251 static int zephyr_send_im(GaimConnection * gc, const char *who, const char *im, GaimConvImFlags flags) 1926 static int zephyr_send_im(GaimConnection * gc, const char *who, const char *im, GaimConvImFlags flags)
1252 { 1927 {
1253 const char *sig; 1928 const char *sig;
1254 1929 zephyr_account *zephyr = gc->proto_data;
1255 if (flags & GAIM_CONV_IM_AUTO_RESP) 1930 if (flags & GAIM_CONV_IM_AUTO_RESP)
1256 sig = "Automated reply:"; 1931 sig = "Automated reply:";
1257 else { 1932 else {
1258 sig = zephyr_get_signature(); 1933 sig = zephyr_get_signature();
1259 } 1934 }
1260 zephyr_send_message("MESSAGE","PERSONAL",local_zephyr_normalize(who),im,sig,""); 1935 zephyr_send_message(zephyr,"MESSAGE","PERSONAL",local_zephyr_normalize(zephyr,who),im,sig,"");
1261 1936
1262 return 1; 1937 return 1;
1263 } 1938 }
1264 1939
1265 static int zephyr_send_message(char* zclass, char* instance, char* recipient, const char *im, 1940 /* Munge the outgoing zephyr so that any quotes or backslashes are
1941 escaped and do not confuse tzc: */
1942
1943 char* zephyr_tzc_escape_msg(const char *message)
1944 {
1945 int pos = 0;
1946 int pos2 = 0;
1947 char *newmsg;
1948
1949 if (message && (strlen(message) > 0)) {
1950 newmsg = g_new0(char,1+strlen(message)*2);
1951 while(pos < strlen(message)) {
1952 if (message[pos]=='\\') {
1953 newmsg[pos2]='\\';
1954 newmsg[pos2+1]='\\';
1955 pos2+=2;
1956 }
1957 else if (message[pos]=='"') {
1958 newmsg[pos2]='\\';
1959 newmsg[pos2+1]='"';
1960 pos2+=2;
1961 }
1962 else {
1963 newmsg[pos2] = message[pos];
1964 pos2++;
1965 }
1966 pos++;
1967 }
1968 } else {
1969 newmsg = g_strdup("");
1970 }
1971 /* fprintf(stderr,"newmsg %s message %s\n",newmsg,message); */
1972 return newmsg;
1973 }
1974
1975 char* zephyr_tzc_deescape_str(const char *message)
1976 {
1977 int pos = 0;
1978 int pos2 = 0;
1979 char *newmsg;
1980
1981 if (message && (strlen(message) > 0)) {
1982 newmsg = g_new0(char,strlen(message)+1);
1983 while(pos < strlen(message)) {
1984 if (message[pos]=='\\') {
1985 pos++;
1986 }
1987 newmsg[pos2] = message[pos];
1988 pos++;pos2++;
1989 }
1990 newmsg[pos2]='\0';
1991 } else {
1992 newmsg = g_strdup("");
1993 }
1994
1995 return newmsg;
1996 }
1997
1998 static int zephyr_send_message(zephyr_account *zephyr,char* zclass, char* instance, char* recipient, const char *im,
1266 const char *sig, char *opcode) 1999 const char *sig, char *opcode)
1267 { 2000 {
1268 char *html_buf; 2001
1269 char *html_buf2; 2002 /* (From the tzc source)
1270 char *buf; 2003 * emacs sends something of the form:
1271 ZNotice_t notice; 2004 * ((class . "MESSAGE")
1272 2005 * (auth . t)
1273 html_buf = html_to_zephyr(im); 2006 * (recipients ("PERSONAL" . "bovik") ("test" . ""))
1274 html_buf2 = gaim_unescape_html(html_buf); 2007 * (sender . "bovik")
1275 2008 * (message . ("Harry Bovik" "my zgram"))
1276 buf = g_strdup_printf("%s%c%s", sig, '\0', html_buf2); 2009 * )
1277 bzero((char *)&notice, sizeof(notice)); 2010 */
1278 2011 char *html_buf;
1279 notice.z_kind = ACKED; 2012 char *html_buf2;
1280 notice.z_port = 0; 2013 html_buf = html_to_zephyr(im);
1281 notice.z_opcode = ""; 2014 html_buf2 = gaim_unescape_html(html_buf);
1282 notice.z_class = zclass; 2015
1283 notice.z_class_inst = instance; 2016 if(use_tzc(zephyr)) {
1284 notice.z_recipient = recipient; 2017 char* zsendstr;
1285 notice.z_sender = 0; 2018 /* CMU cclub tzc doesn't grok opcodes for now */
1286 notice.z_default_format = "Class $class, Instance $instance:\n" "To: @bold($recipient) at $time $date\n" "From: @bold($1) <$sender>\n\n$2"; 2019 char* tzc_sig = zephyr_tzc_escape_msg(sig);
1287 notice.z_message_len = strlen(html_buf2) + strlen(sig) + 2; 2020 char *tzc_body = zephyr_tzc_escape_msg(html_buf2);
1288 notice.z_message = buf; 2021 zsendstr = g_strdup_printf("((tzcfodder . send) (class . \"%s\") (auth . t) (recipients (\"%s\" . \"%s\")) (message . (\"%s\" \"%s\")) ) \n",
1289 notice.z_opcode = g_strdup(opcode); 2022 zclass, instance, recipient, tzc_sig, tzc_body);
1290 gaim_debug_info("zephyr","About to send notice"); 2023 /* fprintf(stderr,"zsendstr = %s\n",zsendstr); */
1291 if (! ZSendNotice(&notice, ZAUTH) == ZERR_NONE) { 2024 write(zephyr->totzc[ZEPHYR_FD_WRITE],zsendstr,strlen(zsendstr));
1292 /* XXX handle errors here */ 2025 g_free(zsendstr);
1293 return 0; 2026 } else if (use_zeph02(zephyr)) {
1294 } 2027 ZNotice_t notice;
1295 gaim_debug_info("zephyr","notice sent"); 2028 char *buf = g_strdup_printf("%s%c%s", sig, '\0', html_buf2);
1296 g_free(buf); 2029 bzero((char *)&notice, sizeof(notice));
2030
2031 notice.z_kind = ACKED;
2032 notice.z_port = 0;
2033 notice.z_opcode = "";
2034 notice.z_class = zclass;
2035 notice.z_class_inst = instance;
2036 notice.z_recipient = recipient;
2037 notice.z_sender = 0;
2038 notice.z_default_format = "Class $class, Instance $instance:\n" "To: @bold($recipient) at $time $date\n" "From: @bold($1) <$sender>\n\n$2";
2039 notice.z_message_len = strlen(html_buf2) + strlen(sig) + 2;
2040 notice.z_message = buf;
2041 notice.z_opcode = g_strdup(opcode);
2042 gaim_debug_info("zephyr","About to send notice");
2043 if (! ZSendNotice(&notice, ZAUTH) == ZERR_NONE) {
2044 /* XXX handle errors here */
2045 return 0;
2046 }
2047 gaim_debug_info("zephyr","notice sent");
2048 g_free(buf);
2049 }
1297 2050
1298 g_free(html_buf2); 2051 g_free(html_buf2);
1299 g_free(html_buf); 2052 g_free(html_buf);
1300 2053
1301 return 1; 2054 return 1;
1302 } 2055 }
1303 2056
1304 static const char *zephyr_normalize(const GaimAccount * account, const char *orig) 2057 static const char *zephyr_normalize(const GaimAccount * account, const char *orig)
1305 { 2058 {
1306 /* returns the string you gave it. Maybe this function shouldn't be here */ 2059 /* returns the string you gave it. Maybe this function shouldn't be here */
1307 static char buf[80]; 2060 char * buf = g_malloc0(80);
2061 /* gaim_debug_error("zephyr","entering zephyr_normalize\n"); */
1308 2062
1309 if (!g_ascii_strcasecmp(orig, "")) { 2063 if (!g_ascii_strcasecmp(orig, "")) {
1310 buf[0] = '\0'; 2064 buf[0] = '\0';
1311 return buf; 2065 return buf;
1312 } else { 2066 } else {
1313 g_snprintf(buf, 80, "%s", orig); 2067 g_snprintf(buf, 80, "%s", orig);
1314 } 2068 }
2069 /* gaim_debug_error("zephyr","leaving zephyr_normalize\n"); */
2070
1315 return buf; 2071 return buf;
1316 } 2072 }
1317 2073
1318 2074
1319 char *local_zephyr_normalize(const char *orig) 2075 char *local_zephyr_normalize(zephyr_account *zephyr,const char *orig)
1320 { 2076 {
1321 /* 2077 /*
1322 Basically the inverse of zephyr_strip_foreign_realm 2078 Basically the inverse of zephyr_strip_foreign_realm
1323 */ 2079 */
1324 static char buf[80]; 2080 char* buf;
1325 2081
1326 if (!g_ascii_strcasecmp(orig, "")) { 2082 if (!g_ascii_strcasecmp(orig, "")) {
1327 buf[0] = '\0'; 2083 return g_strdup("");
1328 return buf; 2084 }
1329 } 2085
1330 2086 if (strchr(orig,'@')) {
1331 if (strchr(orig, '@')) { 2087 buf = g_strdup_printf("%s",orig);
1332 g_snprintf(buf, 80, "%s", orig);
1333 } else { 2088 } else {
1334 g_snprintf(buf, 80, "%s@%s", orig, gaim_zephyr_get_realm()); 2089 buf = g_strdup_printf("%s@%s",orig,zephyr->realm);
1335 } 2090 }
1336 return buf; 2091 return buf;
1337 } 2092 }
1338 2093
1339 static void zephyr_zloc(GaimConnection *gc, const char *who) 2094 static void zephyr_zloc(GaimConnection *gc, const char *who)
1340 { 2095 {
1341 ZAsyncLocateData_t ald; 2096 ZAsyncLocateData_t ald;
1342 gchar* normalized_who = local_zephyr_normalize(who); 2097 zephyr_account *zephyr = gc->proto_data;
1343 zephyr_account *zephyr = gc->proto_data; 2098 gchar* normalized_who = local_zephyr_normalize(zephyr,who);
1344 2099
1345 if (ZRequestLocations(normalized_who, &ald, UNACKED, ZAUTH) == ZERR_NONE) { 2100 if (use_zeph02(zephyr)) {
1346 zephyr->pending_zloc_names = g_list_append(zephyr->pending_zloc_names, 2101 if (ZRequestLocations(normalized_who, &ald, UNACKED, ZAUTH) == ZERR_NONE) {
1347 g_strdup(normalized_who)); 2102 zephyr->pending_zloc_names = g_list_append(zephyr->pending_zloc_names,
1348 } else { 2103 g_strdup(normalized_who));
1349 /* XXX deal with errors somehow */ 2104 } else {
2105 /* XXX deal with errors somehow */
2106 }
2107 } else if (use_tzc(zephyr)) {
2108 char* zlocstr = g_strdup_printf("((tzcfodder . zlocate) \"%s\")\n",normalized_who);
2109 zephyr->pending_zloc_names = g_list_append(zephyr->pending_zloc_names, g_strdup(normalized_who));
2110 write(zephyr->totzc[ZEPHYR_FD_WRITE],zlocstr,strlen(zlocstr));
2111 g_free(zlocstr);
1350 } 2112 }
1351 } 2113 }
1352 2114
1353 static void zephyr_set_away(GaimConnection * gc, const char *state, const char *msg) 2115 static void zephyr_set_away(GaimConnection * gc, const char *state, const char *msg)
1354 { 2116 {
2117 zephyr_account *zephyr = gc->proto_data;
1355 if (gc->away) { 2118 if (gc->away) {
1356 g_free(gc->away); 2119 g_free(gc->away);
1357 gc->away = NULL; 2120 gc->away = NULL;
1358 } 2121 }
1359 2122
1360 if (!g_ascii_strcasecmp(state, _("Hidden"))) { 2123 if (!g_ascii_strcasecmp(state, _("Hidden"))) {
1361 /* XXX handle errors */ 2124 /* XXX handle errors */
1362 ZSetLocation(EXPOSE_OPSTAFF); 2125 if (use_zeph02(zephyr)) {
2126 ZSetLocation(EXPOSE_OPSTAFF);
2127 } else {
2128 char *zexpstr = g_strdup_printf("((tzcfodder . set-location) (hostname . \"%s\") (exposure . \"%s\"))\n",zephyr->ourhost,EXPOSE_OPSTAFF);
2129 write(zephyr->totzc[ZEPHYR_FD_WRITE],zexpstr,strlen(zexpstr));
2130 g_free(zexpstr);
2131 }
1363 gc->away = g_strdup(""); 2132 gc->away = g_strdup("");
1364 } 2133 }
1365 else if (!g_ascii_strcasecmp(state, _("Online"))) { 2134 else if (!g_ascii_strcasecmp(state, _("Online"))) {
1366 /* XXX handle errors */ 2135 /* XXX handle errors */
1367 ZSetLocation(get_exposure_level()); 2136 if (use_zeph02(zephyr)) {
2137 ZSetLocation(get_exposure_level());
2138 }
2139 else {
2140 char *zexpstr = g_strdup_printf("((tzcfodder . set-location) (hostname . \"%s\") (exposure . \"%s\"))\n",zephyr->ourhost,zephyr->exposure);
2141 write(zephyr->totzc[ZEPHYR_FD_WRITE],zexpstr,strlen(zexpstr));
2142 g_free(zexpstr);
2143 }
1368 } 2144 }
1369 else /* state is GAIM_AWAY_CUSTOM */ if (msg) 2145 else /* state is GAIM_AWAY_CUSTOM */ if (msg)
1370 gc->away = g_strdup(msg); 2146 gc->away = g_strdup(msg);
1371 } 2147 }
1372 2148
1407 return m; 2183 return m;
1408 } 2184 }
1409 2185
1410 /* Called when the server notifies us a message couldn't get sent */ 2186 /* Called when the server notifies us a message couldn't get sent */
1411 2187
1412 static void zephyr_subscribe_failed(GaimConnection *gc,ZSubscription_t *sub) 2188 static void zephyr_subscribe_failed(GaimConnection *gc,char * z_class, char *z_instance, char * z_recipient, char* z_galaxy)
1413 { 2189 {
1414 gchar* subscribe_failed = g_strdup_printf(_("Attempt to subscribe to %s,%s,%s failed"), sub->zsub_class, sub->zsub_classinst,sub->zsub_recipient); 2190 gchar* subscribe_failed = g_strdup_printf(_("Attempt to subscribe to %s,%s,%s failed"), z_class, z_instance,z_recipient);
1415 gaim_notify_error(gc,"", subscribe_failed, NULL); 2191 gaim_notify_error(gc,"", subscribe_failed, NULL);
1416 g_free(subscribe_failed); 2192 g_free(subscribe_failed);
1417 } 2193 }
1418 2194
1419 static void zephyr_join_chat(GaimConnection * gc, GHashTable * data) 2195 static void zephyr_join_chat(GaimConnection * gc, GHashTable * data)
1420 { 2196 {
1421 ZSubscription_t sub; 2197 /* ZSubscription_t sub; */
1422 zephyr_triple *zt1, *zt2; 2198 zephyr_triple *zt1, *zt2;
1423 const char *classname; 2199 const char *classname;
1424 const char *instname; 2200 const char *instname;
1425 const char *recip; 2201 const char *recip;
1426 zephyr_account *zephyr=gc->proto_data; 2202 zephyr_account *zephyr=gc->proto_data;
1427 classname = g_hash_table_lookup(data, "class"); 2203 classname = g_hash_table_lookup(data, "class");
1428 instname = g_hash_table_lookup(data, "instance"); 2204 instname = g_hash_table_lookup(data, "instance");
1429 recip = g_hash_table_lookup(data, "recipient"); 2205 recip = g_hash_table_lookup(data, "recipient");
1430 2206
1431 2207
1432 if (!classname) 2208 if (!classname)
1433 return; 2209 return;
1434 2210
1435 if (!g_ascii_strcasecmp(classname,"%host%")) 2211 if (!g_ascii_strcasecmp(classname,"%host%"))
1436 classname = g_strdup(zephyr->ourhost); 2212 classname = g_strdup(zephyr->ourhost);
1437 if (!g_ascii_strcasecmp(classname,"%canon%")) 2213 if (!g_ascii_strcasecmp(classname,"%canon%"))
1438 classname = g_strdup(zephyr->ourhostcanon); 2214 classname = g_strdup(zephyr->ourhostcanon);
1439 2215
1440 if (!instname || !strlen(instname)) 2216 if (!instname || !strlen(instname))
1441 instname = "*"; 2217 instname = "*";
1442 2218
1443 if (!g_ascii_strcasecmp(instname,"%host%")) 2219 if (!g_ascii_strcasecmp(instname,"%host%"))
1444 instname = g_strdup(zephyr->ourhost); 2220 instname = g_strdup(zephyr->ourhost);
1445 if (!g_ascii_strcasecmp(instname,"%canon%")) 2221 if (!g_ascii_strcasecmp(instname,"%canon%"))
1446 instname = g_strdup(zephyr->ourhostcanon); 2222 instname = g_strdup(zephyr->ourhostcanon);
1447 2223
1448 if (!recip || (*recip == '*')) 2224 if (!recip || (*recip == '*'))
1449 recip = ""; 2225 recip = "";
1450 if (!g_ascii_strcasecmp(recip, "%me%")) 2226 if (!g_ascii_strcasecmp(recip, "%me%"))
1451 recip = gaim_zephyr_get_sender(); 2227 recip = zephyr->username;
1452 2228
1453 zt1 = new_triple(gc->proto_data,classname, instname, recip); 2229 zt1 = new_triple(gc->proto_data,classname, instname, recip);
1454 zt2 = find_sub_by_triple(gc->proto_data,zt1); 2230 zt2 = find_sub_by_triple(gc->proto_data,zt1);
1455 if (zt2) { 2231 if (zt2) {
1456 free_triple(zt1); 2232 free_triple(zt1);
1457 if (!zt2->open) { 2233 if (!zt2->open) {
1458 if (!g_ascii_strcasecmp(instname,"*")) 2234 if (!g_ascii_strcasecmp(instname,"*"))
1459 instname = "PERSONAL"; 2235 instname = "PERSONAL";
1460 serv_got_joined_chat(gc, zt2->id, zt2->name); 2236 serv_got_joined_chat(gc, zt2->id, zt2->name);
1461 zephyr_chat_set_topic(gc,zt2->id,instname); 2237 zephyr_chat_set_topic(gc,zt2->id,instname);
1462 zt2->open = TRUE; 2238 zt2->open = TRUE;
1463 } 2239 }
1464 return; 2240 return;
1465 } 2241 }
1466 2242
1467 sub.zsub_class = zt1->class; 2243 /* sub.zsub_class = zt1->class;
1468 sub.zsub_classinst = zt1->instance; 2244 sub.zsub_classinst = zt1->instance;
1469 sub.zsub_recipient = zt1->recipient; 2245 sub.zsub_recipient = zt1->recipient; */
1470 2246
1471 if (ZSubscribeTo(&sub, 1, 0) != ZERR_NONE) { 2247 if (zephyr_subscribe_to(zephyr,zt1->class,zt1->instance,zt1->recipient,NULL) != ZERR_NONE) {
1472 /* XXX output better subscription information */ 2248 /* XXX output better subscription information */
1473 zephyr_subscribe_failed(gc,&sub); 2249 zephyr_subscribe_failed(gc,zt1->class,zt1->instance,zt1->recipient,NULL);
1474 free_triple(zt1); 2250 free_triple(zt1);
1475 return; 2251 return;
1476 } 2252 }
1477 2253
1478 zephyr->subscrips = g_slist_append(zephyr->subscrips, zt1); 2254 zephyr->subscrips = g_slist_append(zephyr->subscrips, zt1);
1479 zt1->open = TRUE; 2255 zt1->open = TRUE;
1480 serv_got_joined_chat(gc, zt1->id, zt1->name); 2256 serv_got_joined_chat(gc, zt1->id, zt1->name);
1481 if (!g_ascii_strcasecmp(instname,"*")) 2257 if (!g_ascii_strcasecmp(instname,"*"))
1482 instname = "PERSONAL"; 2258 instname = "PERSONAL";
1483 zephyr_chat_set_topic(gc,zt1->id,instname); 2259 zephyr_chat_set_topic(gc,zt1->id,instname);
1484 } 2260 }
1485 2261
1486 static void zephyr_chat_leave(GaimConnection * gc, int id) 2262 static void zephyr_chat_leave(GaimConnection * gc, int id)
1487 { 2263 {
1488 zephyr_triple *zt; 2264 zephyr_triple *zt;
1489 zephyr_account *zephyr = gc->proto_data; 2265 zephyr_account *zephyr = gc->proto_data;
1490 zt = find_sub_by_id(zephyr,id); 2266 zt = find_sub_by_id(zephyr,id);
2267
1491 if (zt) { 2268 if (zt) {
1492 zt->open = FALSE; 2269 zt->open = FALSE;
1493 zt->id = ++(zephyr->last_id); 2270 zt->id = ++(zephyr->last_id);
1494 } 2271 }
1495 } 2272 }
1512 continue; 2289 continue;
1513 if(!(inst = g_hash_table_lookup(chat->components, "instance"))) 2290 if(!(inst = g_hash_table_lookup(chat->components, "instance")))
1514 inst = g_strdup(""); 2291 inst = g_strdup("");
1515 if(!(recip = g_hash_table_lookup(chat->components, "recipient"))) 2292 if(!(recip = g_hash_table_lookup(chat->components, "recipient")))
1516 recip = g_strdup(""); 2293 recip = g_strdup("");
2294 /* gaim_debug_info("zephyr","in zephyr_find_blist_chat name: %s\n",name?name:""); */
1517 triple = g_strsplit(name,",",3); 2295 triple = g_strsplit(name,",",3);
1518 if (!g_ascii_strcasecmp(triple[0],zclass) && !g_ascii_strcasecmp(triple[1],inst) && !g_ascii_strcasecmp(triple[2],recip)) 2296 if (!g_ascii_strcasecmp(triple[0],zclass) && !g_ascii_strcasecmp(triple[1],inst) && !g_ascii_strcasecmp(triple[2],recip))
1519 return chat; 2297 return chat;
1520 2298
1521 } 2299 }
1527 return "zephyr"; 2305 return "zephyr";
1528 } 2306 }
1529 2307
1530 static int zephyr_send_typing(GaimConnection *gc, const char *who, int typing) { 2308 static int zephyr_send_typing(GaimConnection *gc, const char *who, int typing) {
1531 gchar *recipient; 2309 gchar *recipient;
2310 zephyr_account *zephyr = gc->proto_data;
2311 if (use_tzc(zephyr))
2312 return 0;
2313
1532 if (!typing) 2314 if (!typing)
1533 return 0; 2315 return 0;
1534 /* XXX We probably should care if this fails. Or maybe we don't want to */ 2316 /* XXX We probably should care if this fails. Or maybe we don't want to */
1535 if (!who) { 2317 if (!who) {
1536 gaim_debug_info("zephyr", "who is null\n"); 2318 gaim_debug_info("zephyr", "who is null\n");
1537 recipient = local_zephyr_normalize(""); 2319 recipient = local_zephyr_normalize(zephyr,"");
1538 } else { 2320 } else {
1539 recipient = local_zephyr_normalize(who); 2321 /* Don't ping broadcast (chat) recipients */
1540 } 2322 /* The strrchr case finds a realm-stripped broadcast subscription
1541 2323 e.g. comma is the last character in the string */
1542 gaim_debug_info("zephyr","about to send typing notification to %s",recipient); 2324 if ((strrchr(who, ',') && ((strrchr(who, ',') == (who+strlen(who)-1)) || ((char *)(strrchr(who, ',')[1] == '@')))))
1543 zephyr_send_message("MESSAGE","PERSONAL",recipient,"","","PING"); 2325 return 0;
1544 gaim_debug_info("zephyr","sent typing notification"); 2326
2327 recipient = local_zephyr_normalize(zephyr,who);
2328 }
2329
2330 gaim_debug_info("zephyr","about to send typing notification to %s\n",recipient);
2331 zephyr_send_message(zephyr,"MESSAGE","PERSONAL",recipient,"","","PING");
2332 gaim_debug_info("zephyr","sent typing notification\n");
1545 return ZEPHYR_TYPING_SEND_TIMEOUT; 2333 return ZEPHYR_TYPING_SEND_TIMEOUT;
1546 } 2334 }
1547 2335
1548 2336
1549 2337
1550 static void zephyr_chat_set_topic(GaimConnection * gc, int id, const char *topic) 2338 static void zephyr_chat_set_topic(GaimConnection * gc, int id, const char *topic)
1551 { 2339 {
1552 zephyr_triple *zt; 2340 zephyr_triple *zt;
1553 GaimConversation *gconv; 2341 GaimConversation *gconv;
1554 GaimConvChat *gcc; 2342 GaimConvChat *gcc;
1555 gchar *topic_utf8; 2343 gchar *topic_utf8;
1556 char *sender = (char *)gaim_zephyr_get_sender(); 2344 zephyr_account* zephyr = gc->proto_data;
2345 char *sender = (char *)zephyr->username;
1557 2346
1558 zt = find_sub_by_id(gc->proto_data,id); 2347 zt = find_sub_by_id(gc->proto_data,id);
1559 gconv = gaim_find_conversation_with_account(zt->name, gc->account); 2348 gconv = gaim_find_conversation_with_account(zt->name, gc->account);
1560 gcc = gaim_conversation_get_chat_data(gconv); 2349 gcc = gaim_conversation_get_chat_data(gconv);
1561 2350
1562 topic_utf8 = zephyr_recv_convert(gc,(gchar *)topic,strlen(topic)); 2351 topic_utf8 = zephyr_recv_convert(gc,(gchar *)topic,strlen(topic));
1563 gaim_conv_chat_set_topic(gcc,sender,topic_utf8); 2352 gaim_conv_chat_set_topic(gcc,sender,topic_utf8);
1564 g_free(topic_utf8); 2353 g_free(topic_utf8);
1565 return; 2354 return;
1566 } 2355 }
1567 2356
1568 /* commands */ 2357 /* commands */
1569 2358
1570 static GaimCmdRet zephyr_gaim_cmd_msg(GaimConversation *conv, 2359 static GaimCmdRet zephyr_gaim_cmd_msg(GaimConversation *conv,
1571 const char *cmd, char **args, char **error, void *data) 2360 const char *cmd, char **args, char **error, void *data)
1572 { 2361 {
1573 char *recipient; 2362 char *recipient;
1574 2363 zephyr_account *zephyr = gaim_conversation_get_gc(conv)->proto_data;
1575 if (!g_ascii_strcasecmp(args[0],"*")) 2364 if (!g_ascii_strcasecmp(args[0],"*"))
1576 return GAIM_CMD_RET_FAILED; /* "*" is not a valid argument */ 2365 return GAIM_CMD_RET_FAILED; /* "*" is not a valid argument */
1577 else 2366 else
1578 recipient = local_zephyr_normalize(args[0]); 2367 recipient = local_zephyr_normalize(zephyr,args[0]);
1579 2368
1580 if (strlen(recipient) < 1) 2369 if (strlen(recipient) < 1)
1581 return GAIM_CMD_RET_FAILED; /* a null recipient is a chat message, not an IM */ 2370 return GAIM_CMD_RET_FAILED; /* a null recipient is a chat message, not an IM */
1582 2371
1583 if (zephyr_send_message("MESSAGE","PERSONAL",recipient,args[1],zephyr_get_signature(),"")) 2372 if (zephyr_send_message(zephyr,"MESSAGE","PERSONAL",recipient,args[1],zephyr_get_signature(),""))
1584 return GAIM_CMD_RET_OK; 2373 return GAIM_CMD_RET_OK;
1585 else 2374 else
1586 return GAIM_CMD_RET_FAILED; 2375 return GAIM_CMD_RET_FAILED;
1587 } 2376 }
1588 2377
1589 static GaimCmdRet zephyr_gaim_cmd_zlocate(GaimConversation *conv, 2378 static GaimCmdRet zephyr_gaim_cmd_zlocate(GaimConversation *conv,
1590 const char *cmd, char **args, char **error, void *data) 2379 const char *cmd, char **args, char **error, void *data)
1591 { 2380 {
1592 zephyr_zloc(gaim_conversation_get_gc(conv),args[0]); 2381 zephyr_zloc(gaim_conversation_get_gc(conv),args[0]);
1593 return GAIM_CMD_RET_OK; 2382 return GAIM_CMD_RET_OK;
1594 } 2383 }
1595 2384
1596 static GaimCmdRet zephyr_gaim_cmd_instance(GaimConversation *conv, 2385 static GaimCmdRet zephyr_gaim_cmd_instance(GaimConversation *conv,
1597 const char *cmd, char **args, char **error, void *data) 2386 const char *cmd, char **args, char **error, void *data)
1598 { 2387 {
1599 /* Currently it sets the instance with leading spaces and 2388 /* Currently it sets the instance with leading spaces and
1600 * all. This might not be the best thing to do, though having 2389 * all. This might not be the best thing to do, though having
1601 * one word isn't ideal either. */ 2390 * one word isn't ideal either. */
1602 2391
1603 GaimConvChat *gcc = gaim_conversation_get_chat_data(conv); 2392 GaimConvChat *gcc = gaim_conversation_get_chat_data(conv);
1604 int id = gcc->id; 2393 int id = gcc->id;
1605 const char* instance = args[0]; 2394 const char* instance = args[0];
1606 zephyr_chat_set_topic(gaim_conversation_get_gc(conv),id,instance); 2395 zephyr_chat_set_topic(gaim_conversation_get_gc(conv),id,instance);
1607 return GAIM_CMD_RET_OK; 2396 return GAIM_CMD_RET_OK;
1608 } 2397 }
1609 2398
1610 static GaimCmdRet zephyr_gaim_cmd_joinchat_cir(GaimConversation *conv, 2399 static GaimCmdRet zephyr_gaim_cmd_joinchat_cir(GaimConversation *conv,
1611 const char *cmd, char **args, char **error, void *data) 2400 const char *cmd, char **args, char **error, void *data)
1612 { 2401 {
1613 /* Join a new zephyr chat */ 2402 /* Join a new zephyr chat */
1614 GHashTable *triple = g_hash_table_new(NULL,NULL); 2403 GHashTable *triple = g_hash_table_new(NULL,NULL);
1615 g_hash_table_insert(triple,"class",args[0]); 2404 g_hash_table_insert(triple,"class",args[0]);
1616 g_hash_table_insert(triple,"instance",args[1]); 2405 g_hash_table_insert(triple,"instance",args[1]);
1617 g_hash_table_insert(triple,"recipient",args[2]); 2406 g_hash_table_insert(triple,"recipient",args[2]);
1618 zephyr_join_chat(gaim_conversation_get_gc(conv),triple); 2407 zephyr_join_chat(gaim_conversation_get_gc(conv),triple);
1619 return GAIM_CMD_RET_OK; 2408 return GAIM_CMD_RET_OK;
1620 } 2409 }
1621 2410
1622 static GaimCmdRet zephyr_gaim_cmd_zi(GaimConversation *conv, 2411 static GaimCmdRet zephyr_gaim_cmd_zi(GaimConversation *conv,
1623 const char *cmd, char **args, char **error, void *data) 2412 const char *cmd, char **args, char **error, void *data)
1624 { 2413 {
1625 /* args = instance, message */ 2414 /* args = instance, message */
1626 if ( zephyr_send_message("message",args[0],"",args[1],zephyr_get_signature(),"")) 2415 zephyr_account *zephyr = gaim_conversation_get_gc(conv)->proto_data;
1627 return GAIM_CMD_RET_OK; 2416 if ( zephyr_send_message(zephyr,"message",args[0],"",args[1],zephyr_get_signature(),""))
1628 else 2417 return GAIM_CMD_RET_OK;
1629 return GAIM_CMD_RET_FAILED; 2418 else
2419 return GAIM_CMD_RET_FAILED;
1630 } 2420 }
1631 2421
1632 static GaimCmdRet zephyr_gaim_cmd_zci(GaimConversation *conv, 2422 static GaimCmdRet zephyr_gaim_cmd_zci(GaimConversation *conv,
1633 const char *cmd, char **args, char **error, void *data) 2423 const char *cmd, char **args, char **error, void *data)
1634 { 2424 {
1635 /* args = class, instance, message */ 2425 /* args = class, instance, message */
1636 if ( zephyr_send_message(args[0],args[1],"",args[2],zephyr_get_signature(),"")) 2426 zephyr_account *zephyr = gaim_conversation_get_gc(conv)->proto_data;
1637 return GAIM_CMD_RET_OK; 2427 if ( zephyr_send_message(zephyr,args[0],args[1],"",args[2],zephyr_get_signature(),""))
1638 else 2428 return GAIM_CMD_RET_OK;
1639 return GAIM_CMD_RET_FAILED; 2429 else
2430 return GAIM_CMD_RET_FAILED;
1640 } 2431 }
1641 2432
1642 static GaimCmdRet zephyr_gaim_cmd_zcir(GaimConversation *conv, 2433 static GaimCmdRet zephyr_gaim_cmd_zcir(GaimConversation *conv,
1643 const char *cmd, char **args, char **error, void *data) 2434 const char *cmd, char **args, char **error, void *data)
1644 { 2435 {
1645 /* args = class, instance, recipient, message */ 2436 /* args = class, instance, recipient, message */
1646 if ( zephyr_send_message(args[0],args[1],args[2],args[3],zephyr_get_signature(),"")) 2437 zephyr_account *zephyr = gaim_conversation_get_gc(conv)->proto_data;
1647 return GAIM_CMD_RET_OK; 2438 if ( zephyr_send_message(zephyr,args[0],args[1],args[2],args[3],zephyr_get_signature(),""))
1648 else 2439 return GAIM_CMD_RET_OK;
1649 return GAIM_CMD_RET_FAILED; 2440 else
2441 return GAIM_CMD_RET_FAILED;
1650 } 2442 }
1651 2443
1652 static GaimCmdRet zephyr_gaim_cmd_zir(GaimConversation *conv, 2444 static GaimCmdRet zephyr_gaim_cmd_zir(GaimConversation *conv,
1653 const char *cmd, char **args, char **error, void *data) 2445 const char *cmd, char **args, char **error, void *data)
1654 { 2446 {
1655 /* args = instance, recipient, message */ 2447 /* args = instance, recipient, message */
1656 if ( zephyr_send_message("message",args[0],args[1],args[2],zephyr_get_signature(),"")) 2448 zephyr_account *zephyr = gaim_conversation_get_gc(conv)->proto_data;
1657 return GAIM_CMD_RET_OK; 2449 if ( zephyr_send_message(zephyr,"message",args[0],args[1],args[2],zephyr_get_signature(),""))
1658 else 2450 return GAIM_CMD_RET_OK;
1659 return GAIM_CMD_RET_FAILED; 2451 else
2452 return GAIM_CMD_RET_FAILED;
1660 } 2453 }
1661 2454
1662 static GaimCmdRet zephyr_gaim_cmd_zc(GaimConversation *conv, 2455 static GaimCmdRet zephyr_gaim_cmd_zc(GaimConversation *conv,
1663 const char *cmd, char **args, char **error, void *data) 2456 const char *cmd, char **args, char **error, void *data)
1664 { 2457 {
1665 /* args = class, message */ 2458 /* args = class, message */
1666 if ( zephyr_send_message(args[0],"PERSONAL","",args[1],zephyr_get_signature(),"")) 2459 zephyr_account *zephyr = gaim_conversation_get_gc(conv)->proto_data;
1667 return GAIM_CMD_RET_OK; 2460 if ( zephyr_send_message(zephyr,args[0],"PERSONAL","",args[1],zephyr_get_signature(),""))
1668 else 2461 return GAIM_CMD_RET_OK;
1669 return GAIM_CMD_RET_FAILED; 2462 else
2463 return GAIM_CMD_RET_FAILED;
1670 } 2464 }
1671 2465
1672 static void zephyr_register_slash_commands() 2466 static void zephyr_register_slash_commands()
1673 { 2467 {
1674 2468
1675 gaim_cmd_register("msg","ws", GAIM_CMD_P_PRPL, 2469 gaim_cmd_register("msg","ws", GAIM_CMD_P_PRPL,
1676 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, 2470 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
1677 "prpl-zephyr", 2471 "prpl-zephyr",
1678 zephyr_gaim_cmd_msg, _("msg &lt;nick&gt; &lt;message&gt;: Send a private message to a user"), NULL); 2472 zephyr_gaim_cmd_msg, _("msg &lt;nick&gt; &lt;message&gt;: Send a private message to a user"), NULL);
1679 2473
1680 gaim_cmd_register("zlocate","w", GAIM_CMD_P_PRPL, 2474 gaim_cmd_register("zlocate","w", GAIM_CMD_P_PRPL,
1681 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, 2475 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
1682 "prpl-zephyr", 2476 "prpl-zephyr",
1683 zephyr_gaim_cmd_zlocate, _("zlocate &lt;nick&gt;: Locate user"), NULL); 2477 zephyr_gaim_cmd_zlocate, _("zlocate &lt;nick&gt;: Locate user"), NULL);
1684 2478
1685 gaim_cmd_register("zl","w", GAIM_CMD_P_PRPL, 2479 gaim_cmd_register("zl","w", GAIM_CMD_P_PRPL,
1686 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, 2480 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
1687 "prpl-zephyr", 2481 "prpl-zephyr",
1688 zephyr_gaim_cmd_zlocate, _("zl &lt;nick&gt;: Locate user"), NULL); 2482 zephyr_gaim_cmd_zlocate, _("zl &lt;nick&gt;: Locate user"), NULL);
1689 2483
1690 gaim_cmd_register("instance","s", GAIM_CMD_P_PRPL, 2484 gaim_cmd_register("instance","s", GAIM_CMD_P_PRPL,
1691 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, 2485 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
1692 "prpl-zephyr", 2486 "prpl-zephyr",
1693 zephyr_gaim_cmd_instance, _("instance &lt;instance&gt;: Set the instance to be used on this class"), NULL); 2487 zephyr_gaim_cmd_instance, _("instance &lt;instance&gt;: Set the instance to be used on this class"), NULL);
1694 2488
1695 gaim_cmd_register("inst","s", GAIM_CMD_P_PRPL, 2489 gaim_cmd_register("inst","s", GAIM_CMD_P_PRPL,
1696 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, 2490 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
1697 "prpl-zephyr", 2491 "prpl-zephyr",
1698 zephyr_gaim_cmd_instance, _("inst &lt;instance&gt;: Set the instance to be used on this class"), NULL); 2492 zephyr_gaim_cmd_instance, _("inst &lt;instance&gt;: Set the instance to be used on this class"), NULL);
1699 2493
1700 gaim_cmd_register("sub", "www", GAIM_CMD_P_PRPL, 2494 gaim_cmd_register("sub", "www", GAIM_CMD_P_PRPL,
1701 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, 2495 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
1702 "prpl-zephyr", 2496 "prpl-zephyr",
1703 zephyr_gaim_cmd_joinchat_cir, 2497 zephyr_gaim_cmd_joinchat_cir,
1704 _("sub &lt;class&gt; &lt;instance&gt; &lt;recipient&gt;: Join a new chat"), NULL); 2498 _("sub &lt;class&gt; &lt;instance&gt; &lt;recipient&gt;: Join a new chat"), NULL);
1705 2499
1706 gaim_cmd_register("zi","ws", GAIM_CMD_P_PRPL, 2500 gaim_cmd_register("zi","ws", GAIM_CMD_P_PRPL,
1707 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, 2501 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
1708 "prpl-zephyr", 2502 "prpl-zephyr",
1709 zephyr_gaim_cmd_zi, _("zi &lt;instance&gt;: Send a message to &lt;message,<i>instance</i>,*&gt;"), NULL); 2503 zephyr_gaim_cmd_zi, _("zi &lt;instance&gt;: Send a message to &lt;message,<i>instance</i>,*&gt;"), NULL);
1710 2504
1711 gaim_cmd_register("zci","wws",GAIM_CMD_P_PRPL, 2505 gaim_cmd_register("zci","wws",GAIM_CMD_P_PRPL,
1712 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, 2506 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
1713 "prpl-zephyr", 2507 "prpl-zephyr",
1714 zephyr_gaim_cmd_zci, 2508 zephyr_gaim_cmd_zci,
1715 _("zci &lt;class&gt; &lt;instance&gt;: Send a message to &lt;<i>class</i>,<i>instance</i>,*&gt;"), NULL); 2509 _("zci &lt;class&gt; &lt;instance&gt;: Send a message to &lt;<i>class</i>,<i>instance</i>,*&gt;"), NULL);
1716 2510
1717 gaim_cmd_register("zcir","wwws",GAIM_CMD_P_PRPL, 2511 gaim_cmd_register("zcir","wwws",GAIM_CMD_P_PRPL,
1718 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, 2512 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
1719 "prpl-zephyr", 2513 "prpl-zephyr",
1720 zephyr_gaim_cmd_zcir, 2514 zephyr_gaim_cmd_zcir,
1721 _("zcir &lt;class&gt; &lt;instance&gt; &lt;recipient&gt;: Send a message to &lt;<i>class</i>,<i>instance</i>,<i>recipient</i>&gt;"), NULL); 2515 _("zcir &lt;class&gt; &lt;instance&gt; &lt;recipient&gt;: Send a message to &lt;<i>class</i>,<i>instance</i>,<i>recipient</i>&gt;"), NULL);
1722 2516
1723 gaim_cmd_register("zir","wws",GAIM_CMD_P_PRPL, 2517 gaim_cmd_register("zir","wws",GAIM_CMD_P_PRPL,
1724 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, 2518 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
1725 "prpl-zephyr", 2519 "prpl-zephyr",
1726 zephyr_gaim_cmd_zir, 2520 zephyr_gaim_cmd_zir,
1727 _("zir &lt;instance&gt; &lt;recipient&gt;: Send a message to &lt;MESSAGE,<i>instance</i>,<i>recipient</i>&gt;"), NULL); 2521 _("zir &lt;instance&gt; &lt;recipient&gt;: Send a message to &lt;MESSAGE,<i>instance</i>,<i>recipient</i>&gt;"), NULL);
1728 2522
1729 gaim_cmd_register("zc","ws", GAIM_CMD_P_PRPL, 2523 gaim_cmd_register("zc","ws", GAIM_CMD_P_PRPL,
1730 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, 2524 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY,
1731 "prpl-zephyr", 2525 "prpl-zephyr",
1732 zephyr_gaim_cmd_zc, _("zc &lt;class&gt;: Send a message to &lt;<i>class</i>,PERSONAL,*&gt;"), NULL); 2526 zephyr_gaim_cmd_zc, _("zc &lt;class&gt;: Send a message to &lt;<i>class</i>,PERSONAL,*&gt;"), NULL);
1733 2527
1734 } 2528 }
1735 2529
1736 2530
2531 static void
2532 zephyr_add_deny(GaimConnection *gc, const char *who)
2533 {
2534 gaim_privacy_deny_add(gc->account,who,1);
2535 }
2536
2537 static void
2538 zephyr_remove_deny(GaimConnection *gc, const char *who)
2539 {
2540 gaim_privacy_deny_remove(gc->account,who,1);
2541 }
2542
2543 static void
2544 zephyr_add_permit(GaimConnection *gc, const char *who)
2545 {
2546 gaim_privacy_permit_add(gc->account,who,1);
2547 }
2548
2549 static void
2550 zephyr_remove_permit(GaimConnection *gc, const char *who)
2551 {
2552 gaim_privacy_permit_remove(gc->account,who,1);
2553 }
2554
2555 static void
2556 zephyr_set_permit_deny(GaimConnection *gc)
2557 {
2558 /* This doesn't have to do anything, since really, we can just check account->perm_deny when deciding whether to di */
2559 return;
2560 }
1737 static int zephyr_resubscribe(GaimConnection *gc) 2561 static int zephyr_resubscribe(GaimConnection *gc)
1738 { 2562 {
1739 /* Resubscribe to the in-memory list of subscriptions and also 2563 /* Resubscribe to the in-memory list of subscriptions and also
1740 unsubscriptions*/ 2564 unsubscriptions*/
1741 zephyr_account *zephyr = gc->proto_data; 2565 zephyr_account *zephyr = gc->proto_data;
1742 GSList *s = zephyr->subscrips; 2566 GSList *s = zephyr->subscrips;
1743 zephyr_triple *zt; 2567 zephyr_triple *zt;
1744 ZSubscription_t zst; 2568 while (s) {
1745 while (s) { 2569 zt = s->data;
1746 zt = s->data; 2570 /* XXX We really should care if this fails */
1747 zst.zsub_class = zt->class; 2571 zephyr_subscribe_to(zephyr,zt->class,zt->instance,zt->recipient,NULL);
1748 zst.zsub_classinst = zt->instance; 2572 s = s->next;
1749 zst.zsub_recipient = zt->recipient; 2573 }
1750 /* XXX We really should care if this fails */ 2574 /* XXX handle unsubscriptions */
1751 ZSubscribeTo(&zst, 1, 0); 2575 return 1;
1752 s = s->next;
1753 }
1754 /* XXX handle unsubscriptions */
1755 return 1;
1756 } 2576 }
1757 2577
1758 2578
1759 static void zephyr_action_resubscribe(GaimPluginAction *action) 2579 static void zephyr_action_resubscribe(GaimPluginAction *action)
1760 { 2580 {
1761 2581
1762 GaimConnection *gc = (GaimConnection *) action->context; 2582 GaimConnection *gc = (GaimConnection *) action->context;
1763 zephyr_resubscribe(gc); 2583 zephyr_resubscribe(gc);
1764 } 2584 }
1765 2585
1766 2586
1767 static void zephyr_action_get_subs_from_server(GaimPluginAction *action) 2587 static void zephyr_action_get_subs_from_server(GaimPluginAction *action)
1768 { 2588 {
1769 GaimConnection *gc = (GaimConnection *) action->context; 2589 GaimConnection *gc = (GaimConnection *) action->context;
1770 zephyr_account *zephyr = gc->proto_data; 2590 zephyr_account *zephyr = gc->proto_data;
1771 gchar *title; 2591 gchar *title;
1772 int retval, nsubs, one,i; 2592 int retval, nsubs, one,i;
1773 ZSubscription_t subs; 2593 ZSubscription_t subs;
1774 GString* subout = g_string_new("Subscription list<br>"); 2594 if (use_zeph02(zephyr)) {
1775 2595 GString* subout = g_string_new("Subscription list<br>");
1776 title = g_strdup_printf("Server subscriptions for %s", gaim_zephyr_get_sender()); 2596
1777 2597 title = g_strdup_printf("Server subscriptions for %s", zephyr->username);
1778 if (zephyr->port == 0) { 2598
1779 gaim_debug(GAIM_DEBUG_ERROR,"zephyr", "error while retrieving port"); 2599 if (zephyr->port == 0) {
1780 return; 2600 gaim_debug(GAIM_DEBUG_ERROR,"zephyr", "error while retrieving port");
1781 } 2601 return;
1782 if ((retval = ZRetrieveSubscriptions(zephyr->port,&nsubs)) != ZERR_NONE) { 2602 }
1783 /* XXX better error handling */ 2603 if ((retval = ZRetrieveSubscriptions(zephyr->port,&nsubs)) != ZERR_NONE) {
1784 gaim_debug(GAIM_DEBUG_ERROR,"zephyr", "error while retrieving subscriptions from server");
1785 return;
1786 }
1787 g_string_append_printf(subout,"Subscription list <br>");
1788 for(i=0;i<nsubs;i++) {
1789 one = 1;
1790 if ((retval = ZGetSubscriptions(&subs,&one)) != ZERR_NONE) {
1791 /* XXX better error handling */ 2604 /* XXX better error handling */
1792 gaim_debug(GAIM_DEBUG_ERROR,"zephyr", "error while retrieving individual subscription"); 2605 gaim_debug(GAIM_DEBUG_ERROR,"zephyr", "error while retrieving subscriptions from server");
1793 return; 2606 return;
1794 } 2607 }
1795 g_string_append_printf(subout, "Class %s Instance %s Recipient %s<br>", 2608 for(i=0;i<nsubs;i++) {
1796 subs.zsub_class, subs.zsub_classinst, 2609 one = 1;
1797 subs.zsub_recipient); 2610 if ((retval = ZGetSubscriptions(&subs,&one)) != ZERR_NONE) {
1798 } 2611 /* XXX better error handling */
1799 gaim_notify_formatted(gc, title, title, NULL, subout->str, NULL, NULL); 2612 gaim_debug(GAIM_DEBUG_ERROR,"zephyr", "error while retrieving individual subscription");
2613 return;
2614 }
2615 g_string_append_printf(subout, "Class %s Instance %s Recipient %s<br>",
2616 subs.zsub_class, subs.zsub_classinst,
2617 subs.zsub_recipient);
2618 }
2619 gaim_notify_formatted(gc, title, title, NULL, subout->str, NULL, NULL);
2620 } else {
2621 /* XXX fix */
2622 gaim_notify_error(gc,"","tzc doesn't support this action",NULL);
2623 }
1800 } 2624 }
1801 2625
1802 2626
1803 static GList *zephyr_actions(GaimPlugin *plugin, gpointer context) 2627 static GList *zephyr_actions(GaimPlugin *plugin, gpointer context)
1804 { 2628 {
1841 NULL, /* change password */ 2665 NULL, /* change password */
1842 NULL, /* add_buddy */ 2666 NULL, /* add_buddy */
1843 NULL, /* add_buddies */ 2667 NULL, /* add_buddies */
1844 NULL, /* remove_buddy */ 2668 NULL, /* remove_buddy */
1845 NULL, /* remove_buddies */ 2669 NULL, /* remove_buddies */
1846 NULL, /* add_permit -- not useful, since anyone can zephyr you by default*/ 2670 zephyr_add_permit, /* add_permit */
1847 NULL, /* XXX add deny -- maybe put an auto "I'm ignoring your zephyrs*/ 2671 zephyr_add_deny, /* add_deny */
1848 NULL, /* remove_permit -- not useful, see add permit */ 2672 zephyr_remove_permit, /* remove_permit */
1849 NULL, /* XXX remove deny -- remove above deny, */ 2673 zephyr_remove_deny, /* remove_deny */
1850 NULL, /* ??? set permit deny */ 2674 zephyr_set_permit_deny, /* set_permit_deny */
1851 NULL, /* --- warn */ 2675 NULL, /* warn -- not supported in zephyr */
1852 zephyr_join_chat, /* join_chat */ 2676 zephyr_join_chat, /* join_chat */
1853 NULL, /* reject_chat */ 2677 NULL, /* reject_chat -- No chat invites*/
1854 NULL, /* chat_invite */ 2678 NULL, /* chat_invite -- No chat invites*/
1855 zephyr_chat_leave, /* chat_leave */ 2679 zephyr_chat_leave, /* chat_leave */
1856 NULL, /* chat_whisper */ 2680 NULL, /* chat_whisper -- No "whispering"*/
1857 zephyr_chat_send, /* chat_send */ 2681 zephyr_chat_send, /* chat_send */
1858 NULL, /* keepalive */ 2682 NULL, /* keepalive -- Not necessary*/
1859 NULL, /* register_user */ 2683 NULL, /* register_user -- Not supported*/
1860 NULL, /* XXX get_cb_info get chat buddy info */ 2684 NULL, /* XXX get_cb_info */
1861 NULL, /* get_cb_away */ 2685 NULL, /* get_cb_away */
1862 NULL, /* alias_buddy */ 2686 NULL, /* alias_buddy */
1863 NULL, /* group_buddy */ 2687 NULL, /* group_buddy */
1864 NULL, /* rename_group */ 2688 NULL, /* rename_group */
1865 NULL, /* ??? buddy_free */ 2689 NULL, /* buddy_free */
1866 NULL, /* convo_closed */ 2690 NULL, /* convo_closed */
1867 zephyr_normalize, /* normalize */ 2691 zephyr_normalize, /* normalize */
1868 NULL, /* XXX set_buddy_icon */ 2692 NULL, /* XXX set_buddy_icon */
1869 NULL, /* remove_group */ 2693 NULL, /* remove_group */
1870 NULL, /* XXX get_cb_real_name */ 2694 NULL, /* XXX get_cb_real_name */
1871 zephyr_chat_set_topic, /* set_chat_topic */ 2695 zephyr_chat_set_topic, /* set_chat_topic */
1872 zephyr_find_blist_chat, /* find_blist_chat */ 2696 zephyr_find_blist_chat, /* find_blist_chat */
1873 NULL, /* roomlist_get_list */ 2697 NULL, /* roomlist_get_list */
1874 NULL, /* roomlist_cancel */ 2698 NULL, /* roomlist_cancel */
1875 NULL, /* roomlist_expand_category */ 2699 NULL, /* roomlist_expand_category */
1876 NULL, /* can_receive_file */ 2700 NULL, /* can_receive_file */
1877 NULL /* send_file */ 2701 NULL /* send_file */
1878 }; 2702 };
1879 2703
1880 static GaimPluginInfo info = { 2704 static GaimPluginInfo info = {
1881 GAIM_PLUGIN_API_VERSION, /**< api_version */ 2705 GAIM_PLUGIN_API_VERSION, /**< api_version */
1882 GAIM_PLUGIN_PROTOCOL, /**< type */ 2706 GAIM_PLUGIN_PROTOCOL, /**< type */
1883 NULL, /**< ui_requirement */ 2707 NULL, /**< ui_requirement */
1884 0, /**< flags */ 2708 0, /**< flags */
1885 NULL, /**< dependencies */ 2709 NULL, /**< dependencies */
1886 GAIM_PRIORITY_DEFAULT, /**< priority */ 2710 GAIM_PRIORITY_DEFAULT, /**< priority */
1887 2711
1888 "prpl-zephyr", /**< id */ 2712 "prpl-zephyr", /**< id */
1889 "Zephyr", /**< name */ 2713 "Zephyr", /**< name */
1890 VERSION, /**< version */ 2714 VERSION, /**< version */
1891 /** summary */ 2715 /** summary */
1892 N_("Zephyr Protocol Plugin"), 2716 N_("Zephyr Protocol Plugin"),
1893 /** description */ 2717 /** description */
1894 N_("Zephyr Protocol Plugin"), 2718 N_("Zephyr Protocol Plugin"),
1895 NULL, /**< author */ 2719 NULL, /**< author */
1896 GAIM_WEBSITE, /**< homepage */ 2720 GAIM_WEBSITE, /**< homepage */
1897 2721
1898 NULL, /**< load */ 2722 NULL, /**< load */
1899 NULL, /**< unload */ 2723 NULL, /**< unload */
1900 NULL, /**< destroy */ 2724 NULL, /**< destroy */
1901 2725
1902 NULL, /**< ui_info */ 2726 NULL, /**< ui_info */
1903 &prpl_info, /**< extra_info */ 2727 &prpl_info, /**< extra_info */
1904 NULL, 2728 NULL,
1905 zephyr_actions 2729 zephyr_actions
1906 }; 2730 };
1907 2731
1908 static void init_plugin(GaimPlugin * plugin) 2732 static void init_plugin(GaimPlugin * plugin)
1909 { 2733 {
1910 GaimAccountOption *option; 2734 GaimAccountOption *option;
1911 char *tmp = get_exposure_level(); 2735 char *tmp = get_exposure_level();
1912 2736
2737 option = gaim_account_option_bool_new("Use tzc", "use_tzc", FALSE);
2738 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
2739
2740 option = gaim_account_option_string_new("tzc command", "tzc_command", "/usr/bin/tzc -e %s");
2741 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
2742
1913 option = gaim_account_option_bool_new(_("Export to .anyone"), "write_anyone", FALSE); 2743 option = gaim_account_option_bool_new(_("Export to .anyone"), "write_anyone", FALSE);
1914 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 2744 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1915 2745
1916 option = gaim_account_option_bool_new(_("Export to .zephyr.subs"), "write_zsubs", FALSE); 2746 option = gaim_account_option_bool_new(_("Export to .zephyr.subs"), "write_zsubs", FALSE);
1917 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 2747 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1921 2751
1922 option = gaim_account_option_string_new(_("Encoding"), "encoding", ZEPHYR_FALLBACK_CHARSET); 2752 option = gaim_account_option_string_new(_("Encoding"), "encoding", ZEPHYR_FALLBACK_CHARSET);
1923 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); 2753 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
1924 2754
1925 my_protocol = plugin; 2755 my_protocol = plugin;
1926 zephyr_register_slash_commands(); 2756 zephyr_register_slash_commands();
1927 } 2757 }
1928 2758
1929 GAIM_INIT_PLUGIN(zephyr, init_plugin, info); 2759 GAIM_INIT_PLUGIN(zephyr, init_plugin, info);