| |
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ |
| |
2 /* |
| |
3 * gaim |
| |
4 * |
| |
5 * Copyright (C) 1998-2001, Mark Spencer <markster@marko.net> |
| |
6 * Some code borrowed from GtkZephyr, by |
| |
7 * Jag/Sean Dilda <agrajag@linuxpower.org>/<smdilda@unity.ncsu.edu> |
| |
8 * http://gtkzephyr.linuxpower.org/ |
| |
9 * |
| |
10 * Some code borrowed from kzephyr, by |
| |
11 * Chris Colohan <colohan+@cs.cmu.edu> |
| |
12 * |
| |
13 * This program is free software; you can redistribute it and/or modify |
| |
14 * it under the terms of the GNU General Public License as published by |
| |
15 * the Free Software Foundation; either version 2 of the License, or |
| |
16 * (at your option) any later version. |
| |
17 * |
| |
18 * This program is distributed in the hope that it will be useful, |
| |
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| |
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| |
21 * GNU General Public License for more details. |
| |
22 * |
| |
23 * You should have received a copy of the GNU General Public License |
| |
24 * along with this program; if not, write to the Free Software |
| |
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| |
26 * |
| |
27 |
| |
28 */ |
| |
29 /* XXX eww */ |
| |
30 #include "libgaim/internal.h" |
| |
31 |
| |
32 #include "accountopt.h" |
| |
33 #include "debug.h" |
| |
34 #include "notify.h" |
| |
35 #include "prpl.h" |
| |
36 #include "server.h" |
| |
37 #include "util.h" |
| |
38 #include "cmds.h" |
| |
39 #include "privacy.h" |
| |
40 #include "version.h" |
| |
41 |
| |
42 #include "zephyr.h" |
| |
43 #include "internal.h" |
| |
44 |
| |
45 #include <strings.h> |
| |
46 |
| |
47 #define ZEPHYR_FALLBACK_CHARSET "ISO-8859-1" |
| |
48 |
| |
49 /* these are deliberately high, since most people don't send multiple "PING"s */ |
| |
50 #define ZEPHYR_TYPING_SEND_TIMEOUT 15 |
| |
51 #define ZEPHYR_TYPING_RECV_TIMEOUT 10 |
| |
52 #define ZEPHYR_FD_READ 0 |
| |
53 #define ZEPHYR_FD_WRITE 1 |
| |
54 |
| |
55 extern Code_t ZGetLocations(ZLocations_t *, int *); |
| |
56 extern Code_t ZSetLocation(char *); |
| |
57 extern Code_t ZUnsetLocation(); |
| |
58 extern Code_t ZGetSubscriptions(ZSubscription_t *, int*); |
| |
59 extern char __Zephyr_realm[]; |
| |
60 typedef struct _zframe zframe; |
| |
61 typedef struct _zephyr_triple zephyr_triple; |
| |
62 typedef struct _zephyr_account zephyr_account; |
| |
63 typedef struct _parse_tree parse_tree; |
| |
64 |
| |
65 typedef enum { |
| |
66 GAIM_ZEPHYR_NONE, /* Non-kerberized ZEPH0.2 */ |
| |
67 GAIM_ZEPHYR_KRB4, /* ZEPH0.2 w/ KRB4 support */ |
| |
68 GAIM_ZEPHYR_TZC, /* tzc executable proxy */ |
| |
69 GAIM_ZEPHYR_INTERGALACTIC_KRB4, /* Kerberized ZEPH0.3 */ |
| |
70 } zephyr_connection_type; |
| |
71 |
| |
72 struct _zephyr_account { |
| |
73 GaimAccount* account; |
| |
74 char *username; |
| |
75 char *realm; |
| |
76 char *encoding; |
| |
77 char* galaxy; /* not yet useful */ |
| |
78 char* krbtkfile; /* not yet useful */ |
| |
79 guint32 nottimer; |
| |
80 guint32 loctimer; |
| |
81 GList *pending_zloc_names; |
| |
82 GSList *subscrips; |
| |
83 int last_id; |
| |
84 unsigned short port; |
| |
85 char ourhost[HOST_NAME_MAX + 1]; |
| |
86 char ourhostcanon[HOST_NAME_MAX + 1]; |
| |
87 zephyr_connection_type connection_type; |
| |
88 int totzc[2]; |
| |
89 int fromtzc[2]; |
| |
90 char *exposure; |
| |
91 pid_t tzc_pid; |
| |
92 gchar *away; |
| |
93 }; |
| |
94 |
| |
95 #define MAXCHILDREN 20 |
| |
96 |
| |
97 struct _parse_tree { |
| |
98 gchar* contents; |
| |
99 parse_tree *children[MAXCHILDREN]; |
| |
100 int num_children; |
| |
101 }; |
| |
102 |
| |
103 parse_tree null_parse_tree = { |
| |
104 "", |
| |
105 {NULL}, |
| |
106 0, |
| |
107 }; |
| |
108 |
| |
109 #define use_none(zephyr) ((zephyr->connection_type == GAIM_ZEPHYR_NONE)?1:0) |
| |
110 #define use_krb4(zephyr) ((zephyr->connection_type == GAIM_ZEPHYR_KRB4)?1:0) |
| |
111 #define use_tzc(zephyr) ((zephyr->connection_type == GAIM_ZEPHYR_TZC)?1:0) |
| |
112 |
| |
113 #define use_zeph02(zephyr) ( (zephyr->connection_type == GAIM_ZEPHYR_NONE)?1: ((zephyr->connection_type == GAIM_ZEPHYR_KRB4)?1:0)) |
| |
114 |
| |
115 /* struct I need for zephyr_to_html */ |
| |
116 struct _zframe { |
| |
117 /* true for everything but @color, since inside the parens of that one is |
| |
118 * the color. */ |
| |
119 gboolean has_closer; |
| |
120 /* @i, @b, etc. */ |
| |
121 const char *env; |
| |
122 /* }=1, ]=2, )=4, >=8 */ |
| |
123 int closer_mask; |
| |
124 /* }, ], ), > */ |
| |
125 char *closer; |
| |
126 /* </i>, </font>, </b>, etc. */ |
| |
127 const char *closing; |
| |
128 /* text including the opening html thingie. */ |
| |
129 GString *text; |
| |
130 /* href for links */ |
| |
131 gboolean is_href; |
| |
132 GString *href; |
| |
133 struct _zframe *enclosing; |
| |
134 }; |
| |
135 |
| |
136 struct _zephyr_triple { |
| |
137 char *class; |
| |
138 char *instance; |
| |
139 char *recipient; |
| |
140 char *name; |
| |
141 gboolean open; |
| |
142 int id; |
| |
143 }; |
| |
144 |
| |
145 #define z_call(func) if (func != ZERR_NONE)\ |
| |
146 return; |
| |
147 #define z_call_r(func) if (func != ZERR_NONE)\ |
| |
148 return TRUE; |
| |
149 |
| |
150 #define z_call_s(func, err) if (func != ZERR_NONE) {\ |
| |
151 gaim_connection_error(gc, err);\ |
| |
152 return;\ |
| |
153 } |
| |
154 |
| |
155 #ifdef WIN32 |
| |
156 extern const char *username; |
| |
157 #endif |
| |
158 |
| |
159 static Code_t zephyr_subscribe_to(zephyr_account* zephyr, char* class, char *instance, char *recipient, char* galaxy) { |
| |
160 |
| |
161 if (use_tzc(zephyr)) { |
| |
162 /* ((tzcfodder . subscribe) ("class" "instance" "recipient")) */ |
| |
163 gchar *zsubstr = g_strdup_printf("((tzcfodder . subscribe) (\"%s\" \"%s\" \"%s\"))\n",class,instance,recipient); |
| |
164 write(zephyr->totzc[ZEPHYR_FD_WRITE],zsubstr,strlen(zsubstr)); |
| |
165 g_free(zsubstr); |
| |
166 return ZERR_NONE; |
| |
167 } |
| |
168 else { |
| |
169 if (use_zeph02(zephyr)) { |
| |
170 ZSubscription_t sub; |
| |
171 sub.zsub_class = class; |
| |
172 sub.zsub_classinst = instance; |
| |
173 sub.zsub_recipient = recipient; |
| |
174 return ZSubscribeTo(&sub,1,0); |
| |
175 } else { |
| |
176 /* This should not happen */ |
| |
177 return -1; |
| |
178 } |
| |
179 } |
| |
180 return -1; |
| |
181 } |
| |
182 |
| |
183 char *local_zephyr_normalize(zephyr_account* zephyr,const char *); |
| |
184 static void zephyr_chat_set_topic(GaimConnection * gc, int id, const char *topic); |
| |
185 char* zephyr_tzc_deescape_str(const char *message); |
| |
186 |
| |
187 static char *zephyr_strip_local_realm(zephyr_account* zephyr,const char* user){ |
| |
188 /* |
| |
189 Takes in a username of the form username or username@realm |
| |
190 and returns: |
| |
191 username, if there is no realm, or the realm is the local realm |
| |
192 or: |
| |
193 username@realm if there is a realm and it is foreign |
| |
194 */ |
| |
195 char *tmp = g_strdup(user); |
| |
196 char *at = strchr(tmp,'@'); |
| |
197 if (at && !g_ascii_strcasecmp(at+1,zephyr->realm)) { |
| |
198 /* We're passed in a username of the form user@users-realm */ |
| |
199 char* tmp2; |
| |
200 *at = '\0'; |
| |
201 tmp2 = g_strdup(tmp); |
| |
202 g_free(tmp); |
| |
203 return tmp2; |
| |
204 } |
| |
205 else { |
| |
206 /* We're passed in a username of the form user or user@foreign-realm */ |
| |
207 return tmp; |
| |
208 } |
| |
209 } |
| |
210 |
| |
211 /* this is so bad, and if Zephyr weren't so fucked up to begin with I |
| |
212 * wouldn't do this. but it is so i will. */ |
| |
213 |
| |
214 /* just for debugging */ |
| |
215 static void handle_unknown(ZNotice_t notice) |
| |
216 { |
| |
217 gaim_debug_error("zephyr","z_packet: %s\n", notice.z_packet); |
| |
218 gaim_debug_error("zephyr","z_version: %s\n", notice.z_version); |
| |
219 gaim_debug_error("zephyr","z_kind: %d\n", (int)(notice.z_kind)); |
| |
220 gaim_debug_error("zephyr","z_class: %s\n", notice.z_class); |
| |
221 gaim_debug_error("zephyr","z_class_inst: %s\n", notice.z_class_inst); |
| |
222 gaim_debug_error("zephyr","z_opcode: %s\n", notice.z_opcode); |
| |
223 gaim_debug_error("zephyr","z_sender: %s\n", notice.z_sender); |
| |
224 gaim_debug_error("zephyr","z_recipient: %s\n", notice.z_recipient); |
| |
225 gaim_debug_error("zephyr","z_message: %s\n", notice.z_message); |
| |
226 gaim_debug_error("zephyr","z_message_len: %d\n", notice.z_message_len); |
| |
227 } |
| |
228 |
| |
229 |
| |
230 static zephyr_triple *new_triple(zephyr_account *zephyr,const char *c, const char *i, const char *r) |
| |
231 { |
| |
232 zephyr_triple *zt; |
| |
233 |
| |
234 zt = g_new0(zephyr_triple, 1); |
| |
235 zt->class = g_strdup(c); |
| |
236 zt->instance = g_strdup(i); |
| |
237 zt->recipient = g_strdup(r); |
| |
238 zt->name = g_strdup_printf("%s,%s,%s", c, i?i:"", r?r:""); |
| |
239 zt->id = ++(zephyr->last_id); |
| |
240 zt->open = FALSE; |
| |
241 return zt; |
| |
242 } |
| |
243 |
| |
244 static void free_triple(zephyr_triple * zt) |
| |
245 { |
| |
246 g_free(zt->class); |
| |
247 g_free(zt->instance); |
| |
248 g_free(zt->recipient); |
| |
249 g_free(zt->name); |
| |
250 g_free(zt); |
| |
251 } |
| |
252 |
| |
253 /* returns true if zt1 is a subset of zt2. This function is used to |
| |
254 determine whether a zephyr sent to zt1 should be placed in the chat |
| |
255 with triple zt2 |
| |
256 |
| |
257 zt1 is a subset of zt2 |
| |
258 iff. the classnames are identical ignoring case |
| |
259 AND. the instance names are identical (ignoring case), or zt2->instance is *. |
| |
260 AND. the recipient names are identical |
| |
261 */ |
| |
262 |
| |
263 static gboolean triple_subset(zephyr_triple * zt1, zephyr_triple * zt2) |
| |
264 { |
| |
265 |
| |
266 if (!zt2) { |
| |
267 gaim_debug_error("zephyr","zt2 doesn't exist\n"); |
| |
268 return FALSE; |
| |
269 } |
| |
270 if (!zt1) { |
| |
271 gaim_debug_error("zephyr","zt1 doesn't exist\n"); |
| |
272 return FALSE; |
| |
273 } |
| |
274 if (!(zt1->class)) { |
| |
275 gaim_debug_error("zephyr","zt1c doesn't exist\n"); |
| |
276 return FALSE; |
| |
277 } |
| |
278 if (!(zt1->instance)) { |
| |
279 gaim_debug_error("zephyr","zt1i doesn't exist\n"); |
| |
280 return FALSE; |
| |
281 } |
| |
282 if (!(zt1->recipient)) { |
| |
283 gaim_debug_error("zephyr","zt1r doesn't exist\n"); |
| |
284 return FALSE; |
| |
285 } |
| |
286 if (!(zt2->class)) { |
| |
287 gaim_debug_error("zephyr","zt2c doesn't exist\n"); |
| |
288 return FALSE; |
| |
289 } |
| |
290 if (!(zt2->recipient)) { |
| |
291 gaim_debug_error("zephyr","zt2r doesn't exist\n"); |
| |
292 return FALSE; |
| |
293 } |
| |
294 if (!(zt2->instance)) { |
| |
295 gaim_debug_error("zephyr","zt2i doesn't exist\n"); |
| |
296 return FALSE; |
| |
297 } |
| |
298 |
| |
299 if (g_ascii_strcasecmp(zt2->class, zt1->class)) { |
| |
300 return FALSE; |
| |
301 } |
| |
302 if (g_ascii_strcasecmp(zt2->instance, zt1->instance) && g_ascii_strcasecmp(zt2->instance, "*")) { |
| |
303 return FALSE; |
| |
304 } |
| |
305 if (g_ascii_strcasecmp(zt2->recipient, zt1->recipient)) { |
| |
306 return FALSE; |
| |
307 } |
| |
308 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); |
| |
309 return TRUE; |
| |
310 } |
| |
311 |
| |
312 static zephyr_triple *find_sub_by_triple(zephyr_account *zephyr,zephyr_triple * zt) |
| |
313 { |
| |
314 zephyr_triple *curr_t; |
| |
315 GSList *curr = zephyr->subscrips; |
| |
316 |
| |
317 while (curr) { |
| |
318 curr_t = curr->data; |
| |
319 if (triple_subset(zt, curr_t)) |
| |
320 return curr_t; |
| |
321 curr = curr->next; |
| |
322 } |
| |
323 return NULL; |
| |
324 } |
| |
325 |
| |
326 static zephyr_triple *find_sub_by_id(zephyr_account *zephyr,int id) |
| |
327 { |
| |
328 zephyr_triple *zt; |
| |
329 GSList *curr = zephyr->subscrips; |
| |
330 |
| |
331 while (curr) { |
| |
332 zt = curr->data; |
| |
333 if (zt->id == id) |
| |
334 return zt; |
| |
335 curr = curr->next; |
| |
336 } |
| |
337 return NULL; |
| |
338 } |
| |
339 |
| |
340 /* |
| |
341 Converts strings to utf-8 if necessary using user specified encoding |
| |
342 */ |
| |
343 |
| |
344 static gchar *zephyr_recv_convert(GaimConnection *gc,gchar *string, int len) |
| |
345 { |
| |
346 gchar *utf8; |
| |
347 GError *err = NULL; |
| |
348 zephyr_account *zephyr = gc->proto_data; |
| |
349 if (g_utf8_validate(string, len, NULL)) { |
| |
350 return g_strdup(string); |
| |
351 } else { |
| |
352 utf8 = g_convert(string, len, "UTF-8", zephyr->encoding, NULL, NULL, &err); |
| |
353 if (err) { |
| |
354 gaim_debug_error("zephyr", "recv conversion error: %s\n", err->message); |
| |
355 utf8 = g_strdup(_("(There was an error converting this message. Check the 'Encoding' option in the Account Editor)")); |
| |
356 g_error_free(err); |
| |
357 } |
| |
358 |
| |
359 return utf8; |
| |
360 } |
| |
361 } |
| |
362 |
| |
363 /* This parses HTML formatting (put out by one of the gtkimhtml widgets |
| |
364 And converts it to zephyr formatting. |
| |
365 It currently deals properly with <b>, <br>, <i>, <font face=...>, <font color=...>, |
| |
366 It ignores <font back=...> |
| |
367 It does |
| |
368 <font size = "1 or 2" -> @small |
| |
369 3 or 4 @medium() |
| |
370 5,6, or 7 @large() |
| |
371 <a href is dealt with by outputting "description <link>" or just "description" as appropriate |
| |
372 */ |
| |
373 |
| |
374 static char *html_to_zephyr(const char *message) |
| |
375 { |
| |
376 zframe *frames, *new_f; |
| |
377 char *ret; |
| |
378 |
| |
379 if (*message == '\0') |
| |
380 return g_strdup(""); |
| |
381 |
| |
382 frames = g_new(zframe, 1); |
| |
383 frames->text = g_string_new(""); |
| |
384 frames->href = NULL; |
| |
385 frames->is_href = FALSE; |
| |
386 frames->enclosing = NULL; |
| |
387 frames->closing = NULL; |
| |
388 frames->env = ""; |
| |
389 frames->has_closer = FALSE; |
| |
390 frames->closer_mask = 15; |
| |
391 |
| |
392 gaim_debug_info("zephyr","html received %s\n",message); |
| |
393 while (*message) { |
| |
394 if (frames->closing && !g_ascii_strncasecmp(message, frames->closing, strlen(frames->closing))) { |
| |
395 zframe *popped; |
| |
396 message += strlen(frames->closing); |
| |
397 popped = frames; |
| |
398 frames = frames->enclosing; |
| |
399 if (popped->is_href) { |
| |
400 frames->href = popped->text; |
| |
401 } else { |
| |
402 g_string_append(frames->text, popped->env); |
| |
403 if (popped->has_closer) { |
| |
404 g_string_append_c(frames->text, |
| |
405 (popped->closer_mask & 1) ? '{' : |
| |
406 (popped->closer_mask & 2) ? '[' : |
| |
407 (popped->closer_mask & 4) ? '(' : |
| |
408 '<'); |
| |
409 } |
| |
410 g_string_append(frames->text, popped->text->str); |
| |
411 if (popped->href) |
| |
412 { |
| |
413 int text_len = strlen(popped->text->str), href_len = strlen(popped->href->str); |
| |
414 if (!((text_len == href_len && !strncmp(popped->href->str, popped->text->str, text_len)) || |
| |
415 (7 + text_len == href_len && !strncmp(popped->href->str, "http://", 7) && |
| |
416 !strncmp(popped->href->str + 7, popped->text->str, text_len)) || |
| |
417 (7 + text_len == href_len && !strncmp(popped->href->str, "mailto:", 7) && |
| |
418 !strncmp(popped->href->str + 7, popped->text->str, text_len)))) { |
| |
419 g_string_append(frames->text, " <"); |
| |
420 g_string_append(frames->text, popped->href->str); |
| |
421 if (popped->closer_mask & ~8) { |
| |
422 g_string_append_c(frames->text, '>'); |
| |
423 popped->closer_mask &= ~8; |
| |
424 } else { |
| |
425 g_string_append(frames->text, "@{>}"); |
| |
426 } |
| |
427 } |
| |
428 g_string_free(popped->href, TRUE); |
| |
429 } |
| |
430 if (popped->has_closer) { |
| |
431 g_string_append_c(frames->text, |
| |
432 (popped->closer_mask & 1) ? '}' : |
| |
433 (popped->closer_mask & 2) ? ']' : |
| |
434 (popped->closer_mask & 4) ? ')' : |
| |
435 '>'); |
| |
436 } |
| |
437 if (!popped->has_closer) |
| |
438 frames->closer_mask = popped->closer_mask; |
| |
439 g_string_free(popped->text, TRUE); |
| |
440 } |
| |
441 g_free(popped); |
| |
442 } else if (*message == '<') { |
| |
443 if (!g_ascii_strncasecmp(message + 1, "i>", 2)) { |
| |
444 new_f = g_new(zframe, 1); |
| |
445 new_f->enclosing = frames; |
| |
446 new_f->text = g_string_new(""); |
| |
447 new_f->href = NULL; |
| |
448 new_f->is_href = FALSE; |
| |
449 new_f->closing = "</i>"; |
| |
450 new_f->env = "@i"; |
| |
451 new_f->has_closer = TRUE; |
| |
452 new_f->closer_mask = 15; |
| |
453 frames = new_f; |
| |
454 message += 3; |
| |
455 } else if (!g_ascii_strncasecmp(message + 1, "b>", 2)) { |
| |
456 new_f = g_new(zframe, 1); |
| |
457 new_f->enclosing = frames; |
| |
458 new_f->text = g_string_new(""); |
| |
459 new_f->href = NULL; |
| |
460 new_f->is_href = FALSE; |
| |
461 new_f->closing = "</b>"; |
| |
462 new_f->env = "@b"; |
| |
463 new_f->has_closer = TRUE; |
| |
464 new_f->closer_mask = 15; |
| |
465 frames = new_f; |
| |
466 message += 3; |
| |
467 } else if (!g_ascii_strncasecmp(message + 1, "br>", 3)) { |
| |
468 g_string_append_c(frames->text, '\n'); |
| |
469 message += 4; |
| |
470 } else if (!g_ascii_strncasecmp(message + 1, "a href=\"", 8)) { |
| |
471 message += 9; |
| |
472 new_f = g_new(zframe, 1); |
| |
473 new_f->enclosing = frames; |
| |
474 new_f->text = g_string_new(""); |
| |
475 new_f->href = NULL; |
| |
476 new_f->is_href = FALSE; |
| |
477 new_f->closing = "</a>"; |
| |
478 new_f->env = ""; |
| |
479 new_f->has_closer = FALSE; |
| |
480 new_f->closer_mask = frames->closer_mask; |
| |
481 frames = new_f; |
| |
482 new_f = g_new(zframe, 1); |
| |
483 new_f->enclosing = frames; |
| |
484 new_f->text = g_string_new(""); |
| |
485 new_f->href = NULL; |
| |
486 new_f->is_href = TRUE; |
| |
487 new_f->closing = "\">"; |
| |
488 new_f->has_closer = FALSE; |
| |
489 new_f->closer_mask = frames->closer_mask; |
| |
490 frames = new_f; |
| |
491 } else if (!g_ascii_strncasecmp(message + 1, "font", 4)) { |
| |
492 new_f = g_new(zframe, 1); |
| |
493 new_f->enclosing = frames; |
| |
494 new_f->text = g_string_new(""); |
| |
495 new_f->href = NULL; |
| |
496 new_f->is_href = FALSE; |
| |
497 new_f->closing = "</font>"; |
| |
498 new_f->has_closer = TRUE; |
| |
499 new_f->closer_mask = 15; |
| |
500 message += 5; |
| |
501 while (*message == ' ') |
| |
502 message++; |
| |
503 if (!g_ascii_strncasecmp(message, "color=\"", 7)) { |
| |
504 message += 7; |
| |
505 new_f->env = "@"; |
| |
506 frames = new_f; |
| |
507 new_f = g_new(zframe, 1); |
| |
508 new_f->enclosing = frames; |
| |
509 new_f->env = "@color"; |
| |
510 new_f->text = g_string_new(""); |
| |
511 new_f->href = NULL; |
| |
512 new_f->is_href = FALSE; |
| |
513 new_f->closing = "\">"; |
| |
514 new_f->has_closer = TRUE; |
| |
515 new_f->closer_mask = 15; |
| |
516 } else if (!g_ascii_strncasecmp(message, "face=\"", 6)) { |
| |
517 message += 6; |
| |
518 new_f->env = "@"; |
| |
519 frames = new_f; |
| |
520 new_f = g_new(zframe, 1); |
| |
521 new_f->enclosing = frames; |
| |
522 new_f->env = "@font"; |
| |
523 new_f->text = g_string_new(""); |
| |
524 new_f->href = NULL; |
| |
525 new_f->is_href = FALSE; |
| |
526 new_f->closing = "\">"; |
| |
527 new_f->has_closer = TRUE; |
| |
528 new_f->closer_mask = 15; |
| |
529 } else if (!g_ascii_strncasecmp(message, "size=\"", 6)) { |
| |
530 message += 6; |
| |
531 if ((*message == '1') || (*message == '2')) { |
| |
532 new_f->env = "@small"; |
| |
533 } else if ((*message == '3') |
| |
534 || (*message == '4')) { |
| |
535 new_f->env = "@medium"; |
| |
536 } else if ((*message == '5') |
| |
537 || (*message == '6') |
| |
538 || (*message == '7')) { |
| |
539 new_f->env = "@large"; |
| |
540 } else { |
| |
541 new_f->env = ""; |
| |
542 new_f->has_closer = FALSE; |
| |
543 new_f->closer_mask = frames->closer_mask; |
| |
544 } |
| |
545 message += 3; |
| |
546 } else { |
| |
547 /* Drop all unrecognized/misparsed font tags */ |
| |
548 new_f->env = ""; |
| |
549 new_f->has_closer = FALSE; |
| |
550 new_f->closer_mask = frames->closer_mask; |
| |
551 while (g_ascii_strncasecmp(message, "\">", 2) != 0) { |
| |
552 message++; |
| |
553 } |
| |
554 if (*message != '\0') |
| |
555 message += 2; |
| |
556 } |
| |
557 frames = new_f; |
| |
558 } else { |
| |
559 /* Catch all for all unrecognized/misparsed <foo> tage */ |
| |
560 g_string_append_c(frames->text, *message++); |
| |
561 } |
| |
562 } else if (*message == '@') { |
| |
563 g_string_append(frames->text, "@@"); |
| |
564 message++; |
| |
565 } else if (*message == '}') { |
| |
566 if (frames->closer_mask & ~1) { |
| |
567 frames->closer_mask &= ~1; |
| |
568 g_string_append_c(frames->text, *message++); |
| |
569 } else { |
| |
570 g_string_append(frames->text, "@[}]"); |
| |
571 message++; |
| |
572 } |
| |
573 } else if (*message == ']') { |
| |
574 if (frames->closer_mask & ~2) { |
| |
575 frames->closer_mask &= ~2; |
| |
576 g_string_append_c(frames->text, *message++); |
| |
577 } else { |
| |
578 g_string_append(frames->text, "@{]}"); |
| |
579 message++; |
| |
580 } |
| |
581 } else if (*message == ')') { |
| |
582 if (frames->closer_mask & ~4) { |
| |
583 frames->closer_mask &= ~4; |
| |
584 g_string_append_c(frames->text, *message++); |
| |
585 } else { |
| |
586 g_string_append(frames->text, "@{)}"); |
| |
587 message++; |
| |
588 } |
| |
589 } else if (!g_ascii_strncasecmp(message, ">", 4)) { |
| |
590 if (frames->closer_mask & ~8) { |
| |
591 frames->closer_mask &= ~8; |
| |
592 g_string_append_c(frames->text, *message++); |
| |
593 } else { |
| |
594 g_string_append(frames->text, "@{>}"); |
| |
595 message += 4; |
| |
596 } |
| |
597 } else { |
| |
598 g_string_append_c(frames->text, *message++); |
| |
599 } |
| |
600 } |
| |
601 ret = frames->text->str; |
| |
602 g_string_free(frames->text, FALSE); |
| |
603 g_free(frames); |
| |
604 gaim_debug_info("zephyr","zephyr outputted %s\n",ret); |
| |
605 return ret; |
| |
606 } |
| |
607 |
| |
608 /* this parses zephyr formatting and converts it to html. For example, if |
| |
609 * you pass in "@{@color(blue)@i(hello)}" you should get out |
| |
610 * "<font color=blue><i>hello</i></font>". */ |
| |
611 static char *zephyr_to_html(const char *message) |
| |
612 { |
| |
613 zframe *frames, *curr; |
| |
614 char *ret; |
| |
615 |
| |
616 frames = g_new(zframe, 1); |
| |
617 frames->text = g_string_new(""); |
| |
618 frames->enclosing = NULL; |
| |
619 frames->closing = ""; |
| |
620 frames->has_closer = FALSE; |
| |
621 frames->closer = NULL; |
| |
622 |
| |
623 while (*message) { |
| |
624 if (*message == '@' && message[1] == '@') { |
| |
625 g_string_append(frames->text, "@"); |
| |
626 message += 2; |
| |
627 } else if (*message == '@') { |
| |
628 int end; |
| |
629 for (end = 1; message[end] && (isalnum(message[end]) || message[end] == '_'); end++); |
| |
630 if (message[end] && |
| |
631 (message[end] == '{' || message[end] == '[' || message[end] == '(' || |
| |
632 !g_ascii_strncasecmp(message + end, "<", 4))) { |
| |
633 zframe *new_f; |
| |
634 char *buf; |
| |
635 buf = g_new0(char, end); |
| |
636 g_snprintf(buf, end, "%s", message + 1); |
| |
637 message += end; |
| |
638 new_f = g_new(zframe, 1); |
| |
639 new_f->enclosing = frames; |
| |
640 new_f->has_closer = TRUE; |
| |
641 new_f->closer = (*message == '{' ? "}" : |
| |
642 *message == '[' ? "]" : |
| |
643 *message == '(' ? ")" : |
| |
644 ">"); |
| |
645 message += (*message == '&' ? 4 : 1); |
| |
646 if (!g_ascii_strcasecmp(buf, "italic") || !g_ascii_strcasecmp(buf, "i")) { |
| |
647 new_f->text = g_string_new("<i>"); |
| |
648 new_f->closing = "</i>"; |
| |
649 } else if (!g_ascii_strcasecmp(buf, "small")) { |
| |
650 new_f->text = g_string_new("<font size=\"1\">"); |
| |
651 new_f->closing = "</font>"; |
| |
652 } else if (!g_ascii_strcasecmp(buf, "medium")) { |
| |
653 new_f->text = g_string_new("<font size=\"3\">"); |
| |
654 new_f->closing = "</font>"; |
| |
655 } else if (!g_ascii_strcasecmp(buf, "large")) { |
| |
656 new_f->text = g_string_new("<font size=\"7\">"); |
| |
657 new_f->closing = "</font>"; |
| |
658 } else if (!g_ascii_strcasecmp(buf, "bold") |
| |
659 || !g_ascii_strcasecmp(buf, "b")) { |
| |
660 new_f->text = g_string_new("<b>"); |
| |
661 new_f->closing = "</b>"; |
| |
662 } else if (!g_ascii_strcasecmp(buf, "font")) { |
| |
663 zframe *extra_f; |
| |
664 extra_f = g_new(zframe, 1); |
| |
665 extra_f->enclosing = frames; |
| |
666 new_f->enclosing = extra_f; |
| |
667 extra_f->text = g_string_new(""); |
| |
668 extra_f->has_closer = FALSE; |
| |
669 extra_f->closer = frames->closer; |
| |
670 extra_f->closing = "</font>"; |
| |
671 new_f->text = g_string_new("<font face=\""); |
| |
672 new_f->closing = "\">"; |
| |
673 } else if (!g_ascii_strcasecmp(buf, "color")) { |
| |
674 zframe *extra_f; |
| |
675 extra_f = g_new(zframe, 1); |
| |
676 extra_f->enclosing = frames; |
| |
677 new_f->enclosing = extra_f; |
| |
678 extra_f->text = g_string_new(""); |
| |
679 extra_f->has_closer = FALSE; |
| |
680 extra_f->closer = frames->closer; |
| |
681 extra_f->closing = "</font>"; |
| |
682 new_f->text = g_string_new("<font color=\""); |
| |
683 new_f->closing = "\">"; |
| |
684 } else { |
| |
685 new_f->text = g_string_new(""); |
| |
686 new_f->closing = ""; |
| |
687 } |
| |
688 frames = new_f; |
| |
689 } else { |
| |
690 /* Not a formatting tag, add the character as normal. */ |
| |
691 g_string_append_c(frames->text, *message++); |
| |
692 } |
| |
693 } else if (frames->closer && !g_ascii_strncasecmp(message, frames->closer, strlen(frames->closer))) { |
| |
694 zframe *popped; |
| |
695 gboolean last_had_closer; |
| |
696 |
| |
697 message += strlen(frames->closer); |
| |
698 if (frames && frames->enclosing) { |
| |
699 do { |
| |
700 popped = frames; |
| |
701 frames = frames->enclosing; |
| |
702 g_string_append(frames->text, popped->text->str); |
| |
703 g_string_append(frames->text, popped->closing); |
| |
704 g_string_free(popped->text, TRUE); |
| |
705 last_had_closer = popped->has_closer; |
| |
706 g_free(popped); |
| |
707 } while (frames && frames->enclosing && !last_had_closer); |
| |
708 } else { |
| |
709 g_string_append_c(frames->text, *message); |
| |
710 } |
| |
711 } else if (*message == '\n') { |
| |
712 g_string_append(frames->text, "<br>"); |
| |
713 message++; |
| |
714 } else { |
| |
715 g_string_append_c(frames->text, *message++); |
| |
716 } |
| |
717 } |
| |
718 /* go through all the stuff that they didn't close */ |
| |
719 while (frames->enclosing) { |
| |
720 curr = frames; |
| |
721 g_string_append(frames->enclosing->text, frames->text->str); |
| |
722 g_string_append(frames->enclosing->text, frames->closing); |
| |
723 g_string_free(frames->text, TRUE); |
| |
724 frames = frames->enclosing; |
| |
725 g_free(curr); |
| |
726 } |
| |
727 ret = frames->text->str; |
| |
728 g_string_free(frames->text, FALSE); |
| |
729 g_free(frames); |
| |
730 return ret; |
| |
731 } |
| |
732 |
| |
733 static gboolean pending_zloc(zephyr_account *zephyr,char *who) |
| |
734 { |
| |
735 GList *curr; |
| |
736 |
| |
737 for (curr = zephyr->pending_zloc_names; curr != NULL; curr = curr->next) { |
| |
738 char* normalized_who = local_zephyr_normalize(zephyr,who); |
| |
739 if (!g_ascii_strcasecmp(normalized_who, (char *)curr->data)) { |
| |
740 g_free((char *)curr->data); |
| |
741 zephyr->pending_zloc_names = g_list_remove(zephyr->pending_zloc_names, curr->data); |
| |
742 return TRUE; |
| |
743 } |
| |
744 } |
| |
745 return FALSE; |
| |
746 } |
| |
747 |
| |
748 /* Called when the server notifies us a message couldn't get sent */ |
| |
749 |
| |
750 static void message_failed(GaimConnection *gc, ZNotice_t notice, struct sockaddr_in from) |
| |
751 { |
| |
752 if (g_ascii_strcasecmp(notice.z_class, "message")) { |
| |
753 gchar* chat_failed = g_strdup_printf(_("Unable to send to chat %s,%s,%s"),notice.z_class,notice.z_class_inst,notice.z_recipient); |
| |
754 gaim_notify_error(gc,"",chat_failed,NULL); |
| |
755 g_free(chat_failed); |
| |
756 } else { |
| |
757 gaim_notify_error(gc, notice.z_recipient, _("User is offline"), NULL); |
| |
758 } |
| |
759 } |
| |
760 |
| |
761 static void handle_message(GaimConnection *gc,ZNotice_t notice) |
| |
762 { |
| |
763 zephyr_account* zephyr = gc->proto_data; |
| |
764 |
| |
765 if (!g_ascii_strcasecmp(notice.z_class, LOGIN_CLASS)) { |
| |
766 /* well, we'll be updating in 20 seconds anyway, might as well ignore this. */ |
| |
767 } else if (!g_ascii_strcasecmp(notice.z_class, LOCATE_CLASS)) { |
| |
768 if (!g_ascii_strcasecmp(notice.z_opcode, LOCATE_LOCATE)) { |
| |
769 int nlocs; |
| |
770 char *user; |
| |
771 GaimBuddy *b; |
| |
772 /* XXX add real error reporting */ |
| |
773 if (ZParseLocations(¬ice, NULL, &nlocs, &user) != ZERR_NONE) |
| |
774 return; |
| |
775 |
| |
776 if ((b = gaim_find_buddy(gc->account, user)) == NULL) { |
| |
777 char* stripped_user = zephyr_strip_local_realm(zephyr,user); |
| |
778 b = gaim_find_buddy(gc->account,stripped_user); |
| |
779 g_free(stripped_user); |
| |
780 } |
| |
781 if ((b && pending_zloc(zephyr,b->name)) || pending_zloc(zephyr,user)) { |
| |
782 ZLocations_t locs; |
| |
783 int one = 1; |
| |
784 GaimNotifyUserInfo *user_info = gaim_notify_user_info_new(); |
| |
785 char *tmp; |
| |
786 |
| |
787 gaim_notify_user_info_add_pair(user_info, _("User"), (b ? b->name : user)); |
| |
788 if (b && b->alias) |
| |
789 gaim_notify_user_info_add_pair(user_info, _("Alias"), b->alias); |
| |
790 |
| |
791 if (!nlocs) { |
| |
792 gaim_notify_user_info_add_pair(user_info, NULL, _("Hidden or not logged-in")); |
| |
793 } |
| |
794 for (; nlocs > 0; nlocs--) { |
| |
795 /* XXX add real error reporting */ |
| |
796 |
| |
797 ZGetLocations(&locs, &one); |
| |
798 tmp = g_strdup_printf(_("<br>At %s since %s"), locs.host, locs.time); |
| |
799 gaim_notify_user_info_add_pair(user_info, _("Location"), tmp); |
| |
800 g_free(tmp); |
| |
801 } |
| |
802 gaim_notify_userinfo(gc, (b ? b->name : user), |
| |
803 user_info, NULL, NULL); |
| |
804 gaim_notify_user_info_destroy(user_info); |
| |
805 } else { |
| |
806 if (nlocs>0) |
| |
807 gaim_prpl_got_user_status(gc->account, b ? b->name : user, "available", NULL); |
| |
808 else |
| |
809 gaim_prpl_got_user_status(gc->account, b ? b->name : user, "offline", NULL); |
| |
810 } |
| |
811 |
| |
812 g_free(user); |
| |
813 } |
| |
814 } else { |
| |
815 char *buf, *buf2, *buf3; |
| |
816 char *send_inst; |
| |
817 GaimConversation *gconv1; |
| |
818 GaimConvChat *gcc; |
| |
819 char *ptr = (char *) notice.z_message + (strlen(notice.z_message) + 1); |
| |
820 int len; |
| |
821 char *sendertmp = g_strdup_printf("%s", zephyr->username); |
| |
822 int signature_length = strlen(notice.z_message); |
| |
823 int message_has_no_body = 0; |
| |
824 GaimMessageFlags flags = 0; |
| |
825 gchar *tmpescape; |
| |
826 |
| |
827 /* Need to deal with 0 length messages to handle typing notification (OPCODE) ping messages */ |
| |
828 /* One field zephyrs would have caused gaim to crash */ |
| |
829 if ( (notice.z_message_len == 0) || (signature_length >= notice.z_message_len - 1)) { |
| |
830 message_has_no_body = 1; |
| |
831 len = 0; |
| |
832 gaim_debug_info("zephyr","message_size %d %d %d\n",len,notice.z_message_len,signature_length); |
| |
833 buf3 = g_strdup(""); |
| |
834 |
| |
835 } else { |
| |
836 len = notice.z_message_len - ( signature_length +1); |
| |
837 gaim_debug_info("zephyr","message_size %d %d %d\n",len,notice.z_message_len,signature_length); |
| |
838 buf = g_malloc(len + 1); |
| |
839 g_snprintf(buf, len + 1, "%s", ptr); |
| |
840 g_strchomp(buf); |
| |
841 tmpescape = g_markup_escape_text(buf, -1); |
| |
842 g_free(buf); |
| |
843 buf2 = zephyr_to_html(tmpescape); |
| |
844 buf3 = zephyr_recv_convert(gc,buf2, strlen(buf2)); |
| |
845 g_free(buf2); |
| |
846 g_free(tmpescape); |
| |
847 } |
| |
848 |
| |
849 if (!g_ascii_strcasecmp(notice.z_class, "MESSAGE") && !g_ascii_strcasecmp(notice.z_class_inst, "PERSONAL") |
| |
850 && !g_ascii_strcasecmp(notice.z_recipient,zephyr->username)) { |
| |
851 gchar* stripped_sender; |
| |
852 if (!g_ascii_strcasecmp(notice.z_message, "Automated reply:")) |
| |
853 flags |= GAIM_MESSAGE_AUTO_RESP; |
| |
854 stripped_sender = zephyr_strip_local_realm(zephyr,notice.z_sender); |
| |
855 |
| |
856 if (!g_ascii_strcasecmp(notice.z_opcode,"PING")) |
| |
857 serv_got_typing(gc,stripped_sender,ZEPHYR_TYPING_RECV_TIMEOUT, GAIM_TYPING); |
| |
858 else { |
| |
859 /* Based on the values of |
| |
860 account->permit_deny, |
| |
861 account->permit, account>deny , and |
| |
862 the buddylist */ |
| |
863 |
| |
864 GSList* l; |
| |
865 gboolean in_deny; |
| |
866 |
| |
867 switch (gc->account->perm_deny) { |
| |
868 case GAIM_PRIVACY_ALLOW_ALL: |
| |
869 in_deny = 0; break; |
| |
870 case GAIM_PRIVACY_DENY_ALL: |
| |
871 in_deny = 1; break; |
| |
872 case GAIM_PRIVACY_ALLOW_USERS: /* See if stripped_sender is in gc->account->permit and allow appropriately */ |
| |
873 in_deny = 1; |
| |
874 for(l=gc->account->permit;l!=NULL;l=l->next) { |
| |
875 if (!gaim_utf8_strcasecmp(stripped_sender, gaim_normalize(gc->account, (char *)l->data))) { |
| |
876 in_deny=0; |
| |
877 break; |
| |
878 } |
| |
879 } |
| |
880 break; |
| |
881 case GAIM_PRIVACY_DENY_USERS: /* See if stripped_sender is in gc->account->deny and deny if so */ |
| |
882 in_deny = 0; |
| |
883 for(l=gc->account->deny;l!=NULL;l=l->next) { |
| |
884 if (!gaim_utf8_strcasecmp(stripped_sender, gaim_normalize(gc->account, (char *)l->data))) { |
| |
885 in_deny=1; |
| |
886 break; |
| |
887 } |
| |
888 } |
| |
889 break; |
| |
890 case GAIM_PRIVACY_ALLOW_BUDDYLIST: |
| |
891 in_deny = 1; |
| |
892 if (gaim_find_buddy(gc->account,stripped_sender)!=NULL) { |
| |
893 in_deny = 0; |
| |
894 } |
| |
895 break; |
| |
896 default: |
| |
897 in_deny=0; break; |
| |
898 } |
| |
899 |
| |
900 if (!in_deny) { |
| |
901 serv_got_im(gc, stripped_sender, buf3, flags, time(NULL)); |
| |
902 } |
| |
903 } |
| |
904 |
| |
905 g_free(stripped_sender); |
| |
906 } else { |
| |
907 zephyr_triple *zt1, *zt2; |
| |
908 gchar *send_inst_utf8; |
| |
909 zephyr_account *zephyr = gc->proto_data; |
| |
910 zt1 = new_triple(gc->proto_data,notice.z_class, notice.z_class_inst, notice.z_recipient); |
| |
911 zt2 = find_sub_by_triple(gc->proto_data,zt1); |
| |
912 if (!zt2) { |
| |
913 /* This is a server supplied subscription */ |
| |
914 zephyr->subscrips = g_slist_append(zephyr->subscrips, new_triple(zephyr,zt1->class,zt1->instance,zt1->recipient)); |
| |
915 zt2 = find_sub_by_triple(gc->proto_data,zt1); |
| |
916 } |
| |
917 |
| |
918 if (!zt2->open) { |
| |
919 zt2->open = TRUE; |
| |
920 serv_got_joined_chat(gc, zt2->id, zt2->name); |
| |
921 zephyr_chat_set_topic(gc,zt2->id,notice.z_class_inst); |
| |
922 } |
| |
923 g_free(sendertmp); /* fix memory leak? */ |
| |
924 /* If the person is in the default Realm, then strip the |
| |
925 Realm from the sender field */ |
| |
926 sendertmp = zephyr_strip_local_realm(zephyr,notice.z_sender); |
| |
927 send_inst = g_strdup_printf("%s %s",sendertmp,notice.z_class_inst); |
| |
928 send_inst_utf8 = zephyr_recv_convert(gc,send_inst, strlen(send_inst)); |
| |
929 if (!send_inst_utf8) { |
| |
930 gaim_debug_error("zephyr","send_inst %s became null\n", send_inst); |
| |
931 send_inst_utf8 = "malformed instance"; |
| |
932 } |
| |
933 |
| |
934 gconv1 = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT, |
| |
935 zt2->name, gc->account); |
| |
936 gcc = gaim_conversation_get_chat_data(gconv1); |
| |
937 |
| |
938 if (!gaim_conv_chat_find_user(gcc, sendertmp)) { |
| |
939 gchar ipaddr[INET_ADDRSTRLEN]; |
| |
940 inet_ntop(AF_INET, ¬ice.z_sender_addr.s_addr, ipaddr, sizeof(ipaddr)); |
| |
941 |
| |
942 gaim_conv_chat_add_user(gcc, sendertmp, ipaddr, GAIM_CBFLAGS_NONE, TRUE); |
| |
943 } |
| |
944 g_free(sendertmp); |
| |
945 serv_got_chat_in(gc, zt2->id, send_inst_utf8, 0, buf3, time(NULL)); |
| |
946 g_free(send_inst); |
| |
947 g_free(send_inst_utf8); |
| |
948 |
| |
949 free_triple(zt1); |
| |
950 } |
| |
951 g_free(buf3); |
| |
952 |
| |
953 } |
| |
954 } |
| |
955 |
| |
956 static int free_parse_tree(parse_tree* tree) { |
| |
957 if (!tree) { |
| |
958 return 0; |
| |
959 } |
| |
960 else { |
| |
961 int i; |
| |
962 if (tree->children) { |
| |
963 for(i=0;i<tree->num_children;i++){ |
| |
964 if (tree->children[i]) { |
| |
965 free_parse_tree(tree->children[i]); |
| |
966 g_free(tree->children[i]); |
| |
967 } |
| |
968 } |
| |
969 } |
| |
970 if ((tree != &null_parse_tree) && (tree->contents != NULL)) |
| |
971 g_free(tree->contents); |
| |
972 |
| |
973 } |
| |
974 return 0; |
| |
975 } |
| |
976 |
| |
977 static parse_tree *tree_child(parse_tree* tree,int index) { |
| |
978 if (index < tree->num_children) { |
| |
979 return tree->children[index]; |
| |
980 } else { |
| |
981 return &null_parse_tree; |
| |
982 } |
| |
983 } |
| |
984 |
| |
985 static parse_tree *find_node(parse_tree* ptree,gchar* key) |
| |
986 { |
| |
987 gchar* tc; |
| |
988 |
| |
989 if (!ptree || ! key) |
| |
990 return &null_parse_tree; |
| |
991 |
| |
992 tc = tree_child(ptree,0)->contents; |
| |
993 |
| |
994 if (ptree->num_children > 0 && tc && !strcasecmp(tc, key)) { |
| |
995 return ptree; |
| |
996 } else { |
| |
997 parse_tree *result = &null_parse_tree; |
| |
998 int i; |
| |
999 for(i = 0; i < ptree->num_children; i++) { |
| |
1000 result = find_node(ptree->children[i],key); |
| |
1001 if(result != &null_parse_tree) { |
| |
1002 break; |
| |
1003 } |
| |
1004 } |
| |
1005 return result; |
| |
1006 } |
| |
1007 } |
| |
1008 |
| |
1009 static parse_tree *parse_buffer(gchar* source, gboolean do_parse) { |
| |
1010 |
| |
1011 parse_tree *ptree = g_new0(parse_tree,1); |
| |
1012 ptree->contents = NULL; |
| |
1013 ptree->num_children=0; |
| |
1014 if (do_parse) { |
| |
1015 unsigned int p = 0; |
| |
1016 while(p < strlen(source)) { |
| |
1017 unsigned int end; |
| |
1018 gchar *newstr; |
| |
1019 |
| |
1020 /* Eat white space: */ |
| |
1021 if(g_ascii_isspace(source[p]) || source[p] == '\001') { |
| |
1022 p++; |
| |
1023 continue; |
| |
1024 } |
| |
1025 |
| |
1026 /* Skip comments */ |
| |
1027 if(source[p] == ';') { |
| |
1028 while(source[p] != '\n' && p < strlen(source)) { |
| |
1029 p++; |
| |
1030 } |
| |
1031 continue; |
| |
1032 } |
| |
1033 |
| |
1034 if(source[p] == '(') { |
| |
1035 int nesting = 0; |
| |
1036 gboolean in_quote = FALSE; |
| |
1037 gboolean escape_next = FALSE; |
| |
1038 p++; |
| |
1039 end = p; |
| |
1040 while(!(source[end] == ')' && nesting == 0 && !in_quote) && end < strlen(source)) { |
| |
1041 if(!escape_next) { |
| |
1042 if(source[end] == '\\') { |
| |
1043 escape_next = TRUE; |
| |
1044 } |
| |
1045 if(!in_quote) { |
| |
1046 if(source[end] == '(') { |
| |
1047 nesting++; |
| |
1048 } |
| |
1049 if(source[end] == ')') { |
| |
1050 nesting--; |
| |
1051 } |
| |
1052 } |
| |
1053 if(source[end] == '"') { |
| |
1054 in_quote = !in_quote; |
| |
1055 } |
| |
1056 } else { |
| |
1057 escape_next = FALSE; |
| |
1058 } |
| |
1059 end++; |
| |
1060 } |
| |
1061 do_parse = TRUE; |
| |
1062 |
| |
1063 } else { |
| |
1064 gchar end_char; |
| |
1065 if(source[p] == '"') { |
| |
1066 end_char = '"'; |
| |
1067 p++; |
| |
1068 } else { |
| |
1069 end_char = ' '; |
| |
1070 } |
| |
1071 do_parse = FALSE; |
| |
1072 |
| |
1073 end = p; |
| |
1074 while(source[end] != end_char && end < strlen(source)) { |
| |
1075 if(source[end] == '\\') |
| |
1076 end++; |
| |
1077 end++; |
| |
1078 } |
| |
1079 } |
| |
1080 newstr = g_new0(gchar, end+1-p); |
| |
1081 strncpy(newstr,source+p,end-p); |
| |
1082 if (ptree->num_children < MAXCHILDREN) { |
| |
1083 /* In case we surpass maxchildren, ignore this */ |
| |
1084 ptree->children[ptree->num_children++] = parse_buffer( newstr, do_parse); |
| |
1085 } else { |
| |
1086 gaim_debug_error("zephyr","too many children in tzc output. skipping\n"); |
| |
1087 } |
| |
1088 g_free(newstr); |
| |
1089 p = end + 1; |
| |
1090 } |
| |
1091 return ptree; |
| |
1092 } else { |
| |
1093 /* XXX does this have to be strdup'd */ |
| |
1094 ptree->contents = g_strdup(source); |
| |
1095 return ptree; |
| |
1096 } |
| |
1097 } |
| |
1098 |
| |
1099 static parse_tree *read_from_tzc(zephyr_account* zephyr){ |
| |
1100 struct timeval tv; |
| |
1101 fd_set rfds; |
| |
1102 int bufsize = 2048; |
| |
1103 char *buf = (char *)calloc(bufsize, 1); |
| |
1104 char *bufcur = buf; |
| |
1105 int selected = 0; |
| |
1106 parse_tree *incoming_msg; |
| |
1107 |
| |
1108 FD_ZERO(&rfds); |
| |
1109 FD_SET(zephyr->fromtzc[ZEPHYR_FD_READ], &rfds); |
| |
1110 tv.tv_sec = 0; |
| |
1111 tv.tv_usec = 0; |
| |
1112 incoming_msg=NULL; |
| |
1113 |
| |
1114 while (select(zephyr->fromtzc[ZEPHYR_FD_READ] + 1, &rfds, NULL, NULL, &tv)) { |
| |
1115 selected = 1; |
| |
1116 read(zephyr->fromtzc[ZEPHYR_FD_READ], bufcur, 1); |
| |
1117 bufcur++; |
| |
1118 if ((bufcur - buf) > (bufsize - 1)) { |
| |
1119 if ((buf = realloc(buf, bufsize * 2)) == NULL) { |
| |
1120 gaim_debug_error("zephyr","Ran out of memory"); |
| |
1121 exit(-1); |
| |
1122 } else { |
| |
1123 bufcur = buf + bufsize; |
| |
1124 bufsize *= 2; |
| |
1125 } |
| |
1126 } |
| |
1127 } |
| |
1128 *bufcur = '\0'; |
| |
1129 |
| |
1130 if (selected) { |
| |
1131 incoming_msg = parse_buffer(buf,TRUE); |
| |
1132 } |
| |
1133 free(buf); |
| |
1134 return incoming_msg; |
| |
1135 } |
| |
1136 |
| |
1137 static gint check_notify_tzc(gpointer data) |
| |
1138 { |
| |
1139 GaimConnection *gc = (GaimConnection *)data; |
| |
1140 zephyr_account* zephyr = gc->proto_data; |
| |
1141 parse_tree *newparsetree = read_from_tzc(zephyr); |
| |
1142 if (newparsetree != NULL) { |
| |
1143 gchar *spewtype; |
| |
1144 if ( (spewtype = tree_child(find_node(newparsetree,"tzcspew"),2)->contents) ) { |
| |
1145 if (!g_ascii_strncasecmp(spewtype,"message",7)) { |
| |
1146 ZNotice_t notice; |
| |
1147 parse_tree *msgnode = tree_child(find_node(newparsetree,"message"),2); |
| |
1148 parse_tree *bodynode = tree_child(msgnode,1); |
| |
1149 /* char *zsig = g_strdup(" "); */ /* gaim doesn't care about zsigs */ |
| |
1150 char *msg = zephyr_tzc_deescape_str(bodynode->contents); |
| |
1151 size_t bufsize = strlen(msg) + 3; |
| |
1152 char *buf = g_new0(char,bufsize); |
| |
1153 g_snprintf(buf,1+strlen(msg)+2," %c%s",'\0',msg); |
| |
1154 bzero((char *)¬ice, sizeof(notice)); |
| |
1155 notice.z_kind = ACKED; |
| |
1156 notice.z_port = 0; |
| |
1157 notice.z_opcode = tree_child(find_node(newparsetree,"opcode"),2)->contents; |
| |
1158 notice.z_class = zephyr_tzc_deescape_str(tree_child(find_node(newparsetree,"class"),2)->contents); |
| |
1159 notice.z_class_inst = tree_child(find_node(newparsetree,"instance"),2)->contents; |
| |
1160 notice.z_recipient = local_zephyr_normalize(zephyr,tree_child(find_node(newparsetree,"recipient"),2)->contents); |
| |
1161 notice.z_sender = local_zephyr_normalize(zephyr,tree_child(find_node(newparsetree,"sender"),2)->contents); |
| |
1162 notice.z_default_format = "Class $class, Instance $instance:\n" "To: @bold($recipient) at $time $date\n" "From: @bold($1) <$sender>\n\n$2"; |
| |
1163 notice.z_message_len = strlen(msg) + 3; |
| |
1164 notice.z_message = buf; |
| |
1165 handle_message(gc, notice); |
| |
1166 g_free(msg); |
| |
1167 /* g_free(zsig); */ |
| |
1168 g_free(buf); |
| |
1169 /* free_parse_tree(msgnode); |
| |
1170 free_parse_tree(bodynode); |
| |
1171 g_free(msg); |
| |
1172 g_free(zsig); |
| |
1173 g_free(buf); |
| |
1174 */ |
| |
1175 } |
| |
1176 else if (!g_ascii_strncasecmp(spewtype,"zlocation",9)) { |
| |
1177 /* check_loc or zephyr_zloc respectively */ |
| |
1178 /* XXX fix */ |
| |
1179 char *user; |
| |
1180 GaimBuddy *b; |
| |
1181 int nlocs = 0; |
| |
1182 parse_tree *locations; |
| |
1183 gchar *locval; |
| |
1184 user = tree_child(find_node(newparsetree,"user"),2)->contents; |
| |
1185 |
| |
1186 if ((b = gaim_find_buddy(gc->account, user)) == NULL) { |
| |
1187 gchar *stripped_user = zephyr_strip_local_realm(zephyr,user); |
| |
1188 b = gaim_find_buddy(gc->account, stripped_user); |
| |
1189 g_free(stripped_user); |
| |
1190 } |
| |
1191 locations = find_node(newparsetree,"locations"); |
| |
1192 locval = tree_child(tree_child(tree_child(tree_child(locations,2),0),0),2)->contents; |
| |
1193 |
| |
1194 if (!locval || !g_ascii_strcasecmp(locval," ") || (strlen(locval) == 0)) { |
| |
1195 nlocs = 0; |
| |
1196 } else { |
| |
1197 nlocs = 1; |
| |
1198 } |
| |
1199 |
| |
1200 if ((b && pending_zloc(zephyr,b->name)) || pending_zloc(zephyr,user) || pending_zloc(zephyr,local_zephyr_normalize(zephyr,user))){ |
| |
1201 GaimNotifyUserInfo *user_info = gaim_notify_user_info_new(); |
| |
1202 char *tmp; |
| |
1203 |
| |
1204 gaim_notify_user_info_add_pair(user_info, _("User"), (b ? b->name : user)); |
| |
1205 |
| |
1206 if (b && b->alias) |
| |
1207 gaim_notify_user_info_add_pair(user_info, _("Alias"), b->alias); |
| |
1208 |
| |
1209 if (!nlocs) { |
| |
1210 gaim_notify_user_info_add_pair(user_info, NULL, _("Hidden or not logged-in")); |
| |
1211 } else { |
| |
1212 tmp = g_strdup_printf(_("<br>At %s since %s"), |
| |
1213 tree_child(tree_child(tree_child(tree_child(locations,2),0),0),2)->contents, |
| |
1214 tree_child(tree_child(tree_child(tree_child(locations,2),0),2),2)->contents); |
| |
1215 gaim_notify_user_info_add_pair(user_info, _("Location"), tmp); |
| |
1216 g_free(tmp); |
| |
1217 } |
| |
1218 |
| |
1219 gaim_notify_userinfo(gc, b ? b->name : user, |
| |
1220 user_info, NULL, NULL); |
| |
1221 gaim_notify_user_info_destroy(user_info); |
| |
1222 } else { |
| |
1223 if (nlocs>0) |
| |
1224 gaim_prpl_got_user_status(gc->account, b ? b->name : user, "available", NULL); |
| |
1225 else |
| |
1226 gaim_prpl_got_user_status(gc->account, b ? b->name : user, "offline", NULL); |
| |
1227 } |
| |
1228 } |
| |
1229 else if (!g_ascii_strncasecmp(spewtype,"subscribed",10)) { |
| |
1230 } |
| |
1231 else if (!g_ascii_strncasecmp(spewtype,"start",5)) { |
| |
1232 } |
| |
1233 else if (!g_ascii_strncasecmp(spewtype,"error",5)) { |
| |
1234 /* XXX handle */ |
| |
1235 } |
| |
1236 } else { |
| |
1237 } |
| |
1238 } else { |
| |
1239 } |
| |
1240 |
| |
1241 free_parse_tree(newparsetree); |
| |
1242 return TRUE; |
| |
1243 } |
| |
1244 |
| |
1245 static gint check_notify_zeph02(gpointer data) |
| |
1246 { |
| |
1247 /* XXX add real error reporting */ |
| |
1248 GaimConnection *gc = (GaimConnection*) data; |
| |
1249 while (ZPending()) { |
| |
1250 ZNotice_t notice; |
| |
1251 struct sockaddr_in from; |
| |
1252 /* XXX add real error reporting */ |
| |
1253 |
| |
1254 z_call_r(ZReceiveNotice(¬ice, &from)); |
| |
1255 |
| |
1256 switch (notice.z_kind) { |
| |
1257 case UNSAFE: |
| |
1258 case UNACKED: |
| |
1259 case ACKED: |
| |
1260 handle_message(gc,notice); |
| |
1261 break; |
| |
1262 case SERVACK: |
| |
1263 if (!(g_ascii_strcasecmp(notice.z_message, ZSRVACK_NOTSENT))) { |
| |
1264 message_failed(gc,notice, from); |
| |
1265 } |
| |
1266 break; |
| |
1267 case CLIENTACK: |
| |
1268 gaim_debug_error("zephyr", "Client ack received\n"); |
| |
1269 default: |
| |
1270 /* we'll just ignore things for now */ |
| |
1271 handle_unknown(notice); |
| |
1272 gaim_debug_error("zephyr", "Unhandled notice.\n"); |
| |
1273 break; |
| |
1274 } |
| |
1275 /* XXX add real error reporting */ |
| |
1276 ZFreeNotice(¬ice); |
| |
1277 } |
| |
1278 |
| |
1279 return TRUE; |
| |
1280 } |
| |
1281 |
| |
1282 #ifdef WIN32 |
| |
1283 |
| |
1284 static gint check_loc(gpointer_data) |
| |
1285 { |
| |
1286 GaimBlistNode *gnode, *cnode, *bnode; |
| |
1287 ZLocations_t locations; |
| |
1288 int numlocs; |
| |
1289 int one = 1; |
| |
1290 |
| |
1291 for (gnode = gaim_get_blist()->root; gnode; gnode = gnode->next) { |
| |
1292 if (!GAIM_BLIST_NODE_IS_GROUP(gnode)) |
| |
1293 continue; |
| |
1294 for (cnode = gnode->child; cnode; cnode = cnode->next) { |
| |
1295 if (!GAIM_BLIST_NODE_IS_CONTACT(cnode)) |
| |
1296 continue; |
| |
1297 for (bnode = cnode->child; bnode; bnode = bnode->next) { |
| |
1298 GaimBuddy *b = (GaimBuddy *) bnode; |
| |
1299 |
| |
1300 if (!GAIM_BLIST_NODE_IS_BUDDY(bnode)) |
| |
1301 continue; |
| |
1302 if (b->account->gc == zgc) { |
| |
1303 char *chk; |
| |
1304 chk = local_zephyr_normalize(b->name); |
| |
1305 ZLocateUser(chk,&numlocs, ZAUTH); |
| |
1306 if (numlocs) { |
| |
1307 int i; |
| |
1308 for(i=0;i<numlocs;i++) { |
| |
1309 ZGetLocations(&locations,&one); |
| |
1310 serv_got_update(zgc,b->name,1,0,0,0,0); |
| |
1311 } |
| |
1312 } |
| |
1313 } |
| |
1314 } |
| |
1315 } |
| |
1316 } |
| |
1317 return TRUE; |
| |
1318 } |
| |
1319 |
| |
1320 #else |
| |
1321 |
| |
1322 static gint check_loc(gpointer data) |
| |
1323 { |
| |
1324 GaimBlistNode *gnode, *cnode, *bnode; |
| |
1325 ZAsyncLocateData_t ald; |
| |
1326 GaimConnection *gc = (GaimConnection *)data; |
| |
1327 zephyr_account *zephyr = gc->proto_data; |
| |
1328 |
| |
1329 if (use_zeph02(zephyr)) { |
| |
1330 ald.user = NULL; |
| |
1331 memset(&(ald.uid), 0, sizeof(ZUnique_Id_t)); |
| |
1332 ald.version = NULL; |
| |
1333 } |
| |
1334 |
| |
1335 for (gnode = gaim_get_blist()->root; gnode; gnode = gnode->next) { |
| |
1336 if (!GAIM_BLIST_NODE_IS_GROUP(gnode)) |
| |
1337 continue; |
| |
1338 for (cnode = gnode->child; cnode; cnode = cnode->next) { |
| |
1339 if (!GAIM_BLIST_NODE_IS_CONTACT(cnode)) |
| |
1340 continue; |
| |
1341 for (bnode = cnode->child; bnode; bnode = bnode->next) { |
| |
1342 GaimBuddy *b = (GaimBuddy *) bnode; |
| |
1343 |
| |
1344 if (!GAIM_BLIST_NODE_IS_BUDDY(bnode)) |
| |
1345 continue; |
| |
1346 if (b->account->gc == gc) { |
| |
1347 const char *chk; |
| |
1348 |
| |
1349 chk = local_zephyr_normalize(zephyr,b->name); |
| |
1350 gaim_debug_info("zephyr","chk: %s b->name %s\n",chk,b->name); |
| |
1351 /* XXX add real error reporting */ |
| |
1352 /* doesn't matter if this fails or not; we'll just move on to the next one */ |
| |
1353 if (use_zeph02(zephyr)) { |
| |
1354 #ifdef WIN32 |
| |
1355 int numlocs; |
| |
1356 int one=1; |
| |
1357 ZLocateUser(chk,&numlocs,ZAUTH); |
| |
1358 if (numlocs) { |
| |
1359 int i; |
| |
1360 for(i=0;i<numlocs;i++) { |
| |
1361 ZGetLocations(&locations,&one); |
| |
1362 if (nlocs>0) |
| |
1363 gaim_prpl_got_user_status(gc->account,b->name,"available",NULL); |
| |
1364 else |
| |
1365 gaim_prpl_got_user_status(gc->account,b->name,"offline",NULL); |
| |
1366 } |
| |
1367 } |
| |
1368 #else |
| |
1369 ZRequestLocations(chk, &ald, UNACKED, ZAUTH); |
| |
1370 g_free(ald.user); |
| |
1371 g_free(ald.version); |
| |
1372 #endif /* WIN32 */ |
| |
1373 } else |
| |
1374 if (use_tzc(zephyr)) { |
| |
1375 gchar *zlocstr = g_strdup_printf("((tzcfodder . zlocate) \"%s\")\n",chk); |
| |
1376 write(zephyr->totzc[ZEPHYR_FD_WRITE],zlocstr,strlen(zlocstr)); |
| |
1377 g_free(zlocstr); |
| |
1378 } |
| |
1379 } |
| |
1380 } |
| |
1381 } |
| |
1382 } |
| |
1383 |
| |
1384 return TRUE; |
| |
1385 } |
| |
1386 |
| |
1387 #endif /* WIN32 */ |
| |
1388 |
| |
1389 static char *get_exposure_level() |
| |
1390 { |
| |
1391 /* XXX add real error reporting */ |
| |
1392 char *exposure = ZGetVariable("exposure"); |
| |
1393 |
| |
1394 if (!exposure) |
| |
1395 return EXPOSE_REALMVIS; |
| |
1396 if (!g_ascii_strcasecmp(exposure, EXPOSE_NONE)) |
| |
1397 return EXPOSE_NONE; |
| |
1398 if (!g_ascii_strcasecmp(exposure, EXPOSE_OPSTAFF)) |
| |
1399 return EXPOSE_OPSTAFF; |
| |
1400 if (!g_ascii_strcasecmp(exposure, EXPOSE_REALMANN)) |
| |
1401 return EXPOSE_REALMANN; |
| |
1402 if (!g_ascii_strcasecmp(exposure, EXPOSE_NETVIS)) |
| |
1403 return EXPOSE_NETVIS; |
| |
1404 if (!g_ascii_strcasecmp(exposure, EXPOSE_NETANN)) |
| |
1405 return EXPOSE_NETANN; |
| |
1406 return EXPOSE_REALMVIS; |
| |
1407 } |
| |
1408 |
| |
1409 static void strip_comments(char *str) |
| |
1410 { |
| |
1411 char *tmp = strchr(str, '#'); |
| |
1412 |
| |
1413 if (tmp) |
| |
1414 *tmp = '\0'; |
| |
1415 g_strchug(str); |
| |
1416 g_strchomp(str); |
| |
1417 } |
| |
1418 |
| |
1419 static void zephyr_inithosts(zephyr_account *zephyr) |
| |
1420 { |
| |
1421 /* XXX This code may not be Win32 clean */ |
| |
1422 struct hostent *hent; |
| |
1423 |
| |
1424 if (gethostname(zephyr->ourhost, sizeof(zephyr->ourhost)) == -1) { |
| |
1425 gaim_debug_error("zephyr", "unable to retrieve hostname, %%host%% and %%canon%% will be wrong in subscriptions and have been set to unknown\n"); |
| |
1426 g_strlcpy(zephyr->ourhost, "unknown", sizeof(zephyr->ourhost)); |
| |
1427 g_strlcpy(zephyr->ourhostcanon, "unknown", sizeof(zephyr->ourhostcanon)); |
| |
1428 return; |
| |
1429 } |
| |
1430 |
| |
1431 if (!(hent = gethostbyname(zephyr->ourhost))) { |
| |
1432 gaim_debug_error("zephyr", "unable to resolve hostname, %%canon%% will be wrong in subscriptions.and has been set to the value of %%host%%, %s\n",zephyr->ourhost); |
| |
1433 g_strlcpy(zephyr->ourhostcanon, zephyr->ourhost, sizeof(zephyr->ourhostcanon)); |
| |
1434 return; |
| |
1435 } |
| |
1436 |
| |
1437 g_strlcpy(zephyr->ourhostcanon, hent->h_name, sizeof(zephyr->ourhostcanon)); |
| |
1438 |
| |
1439 return; |
| |
1440 } |
| |
1441 |
| |
1442 static void process_zsubs(zephyr_account *zephyr) |
| |
1443 { |
| |
1444 /* Loads zephyr chats "(subscriptions) from ~/.zephyr.subs, and |
| |
1445 registers (subscribes to) them on the server */ |
| |
1446 |
| |
1447 /* XXX deal with unsubscriptions */ |
| |
1448 /* XXX deal with punts */ |
| |
1449 |
| |
1450 FILE *f; |
| |
1451 gchar *fname; |
| |
1452 gchar buff[BUFSIZ]; |
| |
1453 |
| |
1454 fname = g_strdup_printf("%s/.zephyr.subs", gaim_home_dir()); |
| |
1455 f = g_fopen(fname, "r"); |
| |
1456 if (f) { |
| |
1457 char **triple; |
| |
1458 char *recip; |
| |
1459 char *z_class; |
| |
1460 char *z_instance; |
| |
1461 char *z_galaxy = NULL; |
| |
1462 |
| |
1463 while (fgets(buff, BUFSIZ, f)) { |
| |
1464 strip_comments(buff); |
| |
1465 if (buff[0]) { |
| |
1466 triple = g_strsplit(buff, ",", 3); |
| |
1467 if (triple[0] && triple[1]) { |
| |
1468 char *tmp = g_strdup_printf("%s", zephyr->username); |
| |
1469 char *atptr; |
| |
1470 |
| |
1471 z_class = triple[0]; |
| |
1472 z_instance = triple[1]; |
| |
1473 if (triple[2] == NULL) { |
| |
1474 recip = g_malloc0(1); |
| |
1475 } else if (!g_ascii_strcasecmp(triple[2], "%me%")) { |
| |
1476 recip = g_strdup_printf("%s", zephyr->username); |
| |
1477 } else if (!g_ascii_strcasecmp(triple[2], "*")) { |
| |
1478 /* wildcard |
| |
1479 * form of class,instance,* */ |
| |
1480 recip = g_malloc0(1); |
| |
1481 } else if (!g_ascii_strcasecmp(triple[2], tmp)) { |
| |
1482 /* form of class,instance,aatharuv@ATHENA.MIT.EDU */ |
| |
1483 recip = g_strdup(triple[2]); |
| |
1484 } else if ((atptr = strchr(triple[2], '@')) != NULL) { |
| |
1485 /* form of class,instance,*@ANDREW.CMU.EDU |
| |
1486 * class,instance,@ANDREW.CMU.EDU |
| |
1487 * If realm is local realm, blank recipient, else |
| |
1488 * @REALM-NAME |
| |
1489 */ |
| |
1490 char *realmat = g_strdup_printf("@%s",zephyr->realm); |
| |
1491 |
| |
1492 if (!g_ascii_strcasecmp(atptr, realmat)) |
| |
1493 recip = g_malloc0(1); |
| |
1494 else |
| |
1495 recip = g_strdup(atptr); |
| |
1496 g_free(realmat); |
| |
1497 } else { |
| |
1498 recip = g_strdup(triple[2]); |
| |
1499 } |
| |
1500 g_free(tmp); |
| |
1501 |
| |
1502 if (!g_ascii_strcasecmp(triple[0],"%host%")) { |
| |
1503 z_class = g_strdup(zephyr->ourhost); |
| |
1504 } else if (!g_ascii_strcasecmp(triple[0],"%canon%")) { |
| |
1505 z_class = g_strdup(zephyr->ourhostcanon); |
| |
1506 } else { |
| |
1507 z_class = g_strdup(triple[0]); |
| |
1508 } |
| |
1509 |
| |
1510 if (!g_ascii_strcasecmp(triple[1],"%host%")) { |
| |
1511 z_instance = g_strdup(zephyr->ourhost); |
| |
1512 } else if (!g_ascii_strcasecmp(triple[1],"%canon%")) { |
| |
1513 z_instance = g_strdup(zephyr->ourhostcanon); |
| |
1514 } else { |
| |
1515 z_instance = g_strdup(triple[1]); |
| |
1516 } |
| |
1517 |
| |
1518 /* There should be some sort of error report listing classes that couldn't be subbed to. |
| |
1519 Not important right now though */ |
| |
1520 |
| |
1521 if (zephyr_subscribe_to(zephyr,z_class, z_instance, recip,z_galaxy) != ZERR_NONE) { |
| |
1522 |
| |
1523 gaim_debug_error("zephyr", "Couldn't subscribe to %s, %s, %s\n", z_class,z_instance,recip); |
| |
1524 } |
| |
1525 |
| |
1526 zephyr->subscrips = g_slist_append(zephyr->subscrips, new_triple(zephyr,z_class,z_instance,recip)); |
| |
1527 /* g_hash_table_destroy(sub_hash_table); */ |
| |
1528 g_free(z_instance); |
| |
1529 g_free(z_class); |
| |
1530 g_free(recip); |
| |
1531 } |
| |
1532 g_strfreev(triple); |
| |
1533 } |
| |
1534 } |
| |
1535 fclose(f); |
| |
1536 } |
| |
1537 } |
| |
1538 |
| |
1539 static void process_anyone(GaimConnection *gc) |
| |
1540 { |
| |
1541 FILE *fd; |
| |
1542 gchar buff[BUFSIZ], *filename; |
| |
1543 GaimGroup *g; |
| |
1544 GaimBuddy *b; |
| |
1545 |
| |
1546 if (!(g = gaim_find_group(_("Anyone")))) { |
| |
1547 g = gaim_group_new(_("Anyone")); |
| |
1548 gaim_blist_add_group(g, NULL); |
| |
1549 } |
| |
1550 |
| |
1551 filename = g_strconcat(gaim_home_dir(), "/.anyone", NULL); |
| |
1552 if ((fd = g_fopen(filename, "r")) != NULL) { |
| |
1553 while (fgets(buff, BUFSIZ, fd)) { |
| |
1554 strip_comments(buff); |
| |
1555 if (buff[0]) { |
| |
1556 if (!(b = gaim_find_buddy(gc->account, buff))) { |
| |
1557 char *stripped_user = zephyr_strip_local_realm(gc->proto_data,buff); |
| |
1558 gaim_debug_info("zephyr","stripped_user %s\n",stripped_user); |
| |
1559 if (!(b = gaim_find_buddy(gc->account,stripped_user))){ |
| |
1560 b = gaim_buddy_new(gc->account, stripped_user, NULL); |
| |
1561 gaim_blist_add_buddy(b, NULL, g, NULL); |
| |
1562 } |
| |
1563 g_free(stripped_user); |
| |
1564 } |
| |
1565 } |
| |
1566 } |
| |
1567 fclose(fd); |
| |
1568 } |
| |
1569 g_free(filename); |
| |
1570 } |
| |
1571 |
| |
1572 static char* normalize_zephyr_exposure(const char* exposure) { |
| |
1573 char *exp2 = g_strstrip(g_ascii_strup(exposure,-1)); |
| |
1574 |
| |
1575 if (!exp2) |
| |
1576 return EXPOSE_REALMVIS; |
| |
1577 if (!g_ascii_strcasecmp(exp2, EXPOSE_NONE)) |
| |
1578 return EXPOSE_NONE; |
| |
1579 if (!g_ascii_strcasecmp(exp2, EXPOSE_OPSTAFF)) |
| |
1580 return EXPOSE_OPSTAFF; |
| |
1581 if (!g_ascii_strcasecmp(exp2, EXPOSE_REALMANN)) |
| |
1582 return EXPOSE_REALMANN; |
| |
1583 if (!g_ascii_strcasecmp(exp2, EXPOSE_NETVIS)) |
| |
1584 return EXPOSE_NETVIS; |
| |
1585 if (!g_ascii_strcasecmp(exp2, EXPOSE_NETANN)) |
| |
1586 return EXPOSE_NETANN; |
| |
1587 return EXPOSE_REALMVIS; |
| |
1588 } |
| |
1589 |
| |
1590 static void zephyr_login(GaimAccount * account) |
| |
1591 { |
| |
1592 GaimConnection *gc; |
| |
1593 zephyr_account *zephyr; |
| |
1594 gboolean read_anyone; |
| |
1595 gboolean read_zsubs; |
| |
1596 gchar *exposure; |
| |
1597 |
| |
1598 gc = gaim_account_get_connection(account); |
| |
1599 read_anyone = gaim_account_get_bool(gc->account,"read_anyone",TRUE); |
| |
1600 read_zsubs = gaim_account_get_bool(gc->account,"read_zsubs",TRUE); |
| |
1601 exposure = (gchar *)gaim_account_get_string(gc->account, "exposure_level", EXPOSE_REALMVIS); |
| |
1602 |
| |
1603 #ifdef WIN32 |
| |
1604 username = gaim_account_get_username(account); |
| |
1605 #endif |
| |
1606 gc->flags |= GAIM_CONNECTION_HTML | GAIM_CONNECTION_NO_BGCOLOR | GAIM_CONNECTION_NO_URLDESC; |
| |
1607 gc->proto_data = zephyr=g_new0(zephyr_account,1); |
| |
1608 |
| |
1609 zephyr->account = account; |
| |
1610 |
| |
1611 /* Make sure that the exposure (visibility) is set to a sane value */ |
| |
1612 zephyr->exposure=g_strdup(normalize_zephyr_exposure(exposure)); |
| |
1613 |
| |
1614 if (gaim_account_get_bool(gc->account,"use_tzc",0)) { |
| |
1615 zephyr->connection_type = GAIM_ZEPHYR_TZC; |
| |
1616 } else { |
| |
1617 zephyr->connection_type = GAIM_ZEPHYR_KRB4; |
| |
1618 } |
| |
1619 |
| |
1620 zephyr->encoding = (char *)gaim_account_get_string(gc->account, "encoding", ZEPHYR_FALLBACK_CHARSET); |
| |
1621 gaim_connection_update_progress(gc, _("Connecting"), 0, 8); |
| |
1622 |
| |
1623 /* XXX z_call_s should actually try to report the com_err determined error */ |
| |
1624 if (use_tzc(zephyr)) { |
| |
1625 pid_t pid; |
| |
1626 /* gaim_connection_error(gc,"tzc not supported yet"); */ |
| |
1627 if ((pipe(zephyr->totzc) != 0) || (pipe(zephyr->fromtzc) != 0)) { |
| |
1628 gaim_debug_error("zephyr", "pipe creation failed. killing\n"); |
| |
1629 exit(-1); |
| |
1630 } |
| |
1631 |
| |
1632 pid = fork(); |
| |
1633 |
| |
1634 if (pid == -1) { |
| |
1635 gaim_debug_error("zephyr", "forking failed\n"); |
| |
1636 exit(-1); |
| |
1637 } |
| |
1638 if (pid == 0) { |
| |
1639 unsigned int i=0; |
| |
1640 gboolean found_ps = FALSE; |
| |
1641 gchar ** tzc_cmd_array = g_strsplit(gaim_account_get_string(gc->account,"tzc_command","/usr/bin/tzc -e %s")," ",0); |
| |
1642 if (close(1) == -1) { |
| |
1643 gaim_debug_error("zephyr", "stdout couldn't be closed. dying\n"); |
| |
1644 exit(-1); |
| |
1645 } |
| |
1646 if (dup2(zephyr->fromtzc[1], 1) == -1) { |
| |
1647 gaim_debug_error("zephyr", "dup2 of stdout failed \n"); |
| |
1648 exit(-1); |
| |
1649 } |
| |
1650 if (close(zephyr->fromtzc[1]) == -1) { |
| |
1651 gaim_debug_error("zephyr", "closing of piped stdout failed\n"); |
| |
1652 exit(-1); |
| |
1653 } |
| |
1654 if (close(0) == -1) { |
| |
1655 gaim_debug_error("zephyr", "stdin couldn't be closed. dying\n"); |
| |
1656 exit(-1); |
| |
1657 } |
| |
1658 if (dup2(zephyr->totzc[0], 0) == -1) { |
| |
1659 gaim_debug_error("zephyr", "dup2 of stdin failed \n"); |
| |
1660 exit(-1); |
| |
1661 } |
| |
1662 if (close(zephyr->totzc[0]) == -1) { |
| |
1663 gaim_debug_error("zephyr", "closing of piped stdin failed\n"); |
| |
1664 exit(-1); |
| |
1665 } |
| |
1666 /* tzc_command should really be of the form |
| |
1667 path/to/tzc -e %s |
| |
1668 or |
| |
1669 ssh username@hostname pathtotzc -e %s |
| |
1670 -- this should not require a password, and ideally should be kerberized ssh -- |
| |
1671 or |
| |
1672 fsh username@hostname pathtotzc -e %s |
| |
1673 */ |
| |
1674 while(tzc_cmd_array[i] != NULL){ |
| |
1675 if (!g_ascii_strncasecmp(tzc_cmd_array[i],"%s",2)) { |
| |
1676 /* fprintf(stderr,"replacing %%s with %s\n",zephyr->exposure); */ |
| |
1677 tzc_cmd_array[i] = g_strdup(zephyr->exposure); |
| |
1678 found_ps = TRUE; |
| |
1679 |
| |
1680 } else { |
| |
1681 /* fprintf(stderr,"keeping %s\n",tzc_cmd_array[i]); */ |
| |
1682 } |
| |
1683 i++; |
| |
1684 } |
| |
1685 |
| |
1686 if (!found_ps) { |
| |
1687 gaim_connection_error(gc,"Tzc command needs %s to set the exposure\n"); |
| |
1688 return; |
| |
1689 } |
| |
1690 |
| |
1691 execvp(tzc_cmd_array[0], tzc_cmd_array); |
| |
1692 } |
| |
1693 else { |
| |
1694 fd_set rfds; |
| |
1695 int bufsize = 2048; |
| |
1696 char *buf = (char *)calloc(bufsize, 1); |
| |
1697 char *bufcur = buf; |
| |
1698 struct timeval tv; |
| |
1699 char *ptr; |
| |
1700 int parenlevel=0; |
| |
1701 char* tempstr; |
| |
1702 int tempstridx; |
| |
1703 |
| |
1704 zephyr->tzc_pid = pid; |
| |
1705 /* wait till we have data to read from ssh */ |
| |
1706 FD_ZERO(&rfds); |
| |
1707 FD_SET(zephyr->fromtzc[ZEPHYR_FD_READ], &rfds); |
| |
1708 |
| |
1709 tv.tv_sec = 10; |
| |
1710 tv.tv_usec = 0; |
| |
1711 |
| |
1712 gaim_debug_info("zephyr", "about to read from tzc\n"); |
| |
1713 |
| |
1714 select(zephyr->fromtzc[ZEPHYR_FD_READ] + 1, &rfds, NULL, NULL, NULL); |
| |
1715 |
| |
1716 FD_ZERO(&rfds); |
| |
1717 FD_SET(zephyr->fromtzc[ZEPHYR_FD_READ], &rfds); |
| |
1718 while (select(zephyr->fromtzc[ZEPHYR_FD_READ] + 1, &rfds, NULL, NULL, &tv)) { |
| |
1719 read(zephyr->fromtzc[ZEPHYR_FD_READ], bufcur, 1); |
| |
1720 bufcur++; |
| |
1721 if ((bufcur - buf) > (bufsize - 1)) { |
| |
1722 if ((buf = realloc(buf, bufsize * 2)) == NULL) { |
| |
1723 exit(-1); |
| |
1724 } else { |
| |
1725 bufcur = buf + bufsize; |
| |
1726 bufsize *= 2; |
| |
1727 } |
| |
1728 } |
| |
1729 FD_ZERO(&rfds); |
| |
1730 FD_SET(zephyr->fromtzc[ZEPHYR_FD_READ], &rfds); |
| |
1731 tv.tv_sec = 10; |
| |
1732 tv.tv_usec = 0; |
| |
1733 |
| |
1734 } |
| |
1735 /* fprintf(stderr, "read from tzc\n"); */ |
| |
1736 *bufcur = '\0'; |
| |
1737 ptr = buf; |
| |
1738 |
| |
1739 /* ignore all tzcoutput till we've received the first (*/ |
| |
1740 while (ptr < bufcur && (*ptr !='(')) { |
| |
1741 ptr++; |
| |
1742 } |
| |
1743 if (ptr >=bufcur) { |
| |
1744 gaim_connection_error(gc,"invalid output by tzc (or bad parsing code)"); |
| |
1745 free(buf); |
| |
1746 return; |
| |
1747 } |
| |
1748 |
| |
1749 while(ptr < bufcur) { |
| |
1750 if (*ptr == '(') { |
| |
1751 parenlevel++; |
| |
1752 } |
| |
1753 else if (*ptr == ')') { |
| |
1754 parenlevel--; |
| |
1755 } |
| |
1756 gaim_debug_info("zephyr","tzc parenlevel is %d\n",parenlevel); |
| |
1757 switch (parenlevel) { |
| |
1758 case 0: |
| |
1759 break; |
| |
1760 case 1: |
| |
1761 /* Search for next beginning (, or for the ending */ |
| |
1762 ptr++; |
| |
1763 while((*ptr != '(') && (*ptr != ')') && (ptr <bufcur)) |
| |
1764 ptr++; |
| |
1765 if (ptr >= bufcur) |
| |
1766 gaim_debug_error("zephyr","tzc parsing error\n"); |
| |
1767 break; |
| |
1768 case 2: |
| |
1769 /* You are probably at |
| |
1770 (foo . bar ) or (foo . "bar") or (foo . chars) or (foo . numbers) or (foo . () ) |
| |
1771 Parse all the data between the first and last f, and move past ) |
| |
1772 */ |
| |
1773 tempstr = g_malloc0(20000); |
| |
1774 tempstridx=0; |
| |
1775 while(parenlevel >1) { |
| |
1776 ptr++; |
| |
1777 if (*ptr == '(') |
| |
1778 parenlevel++; |
| |
1779 if (*ptr == ')') |
| |
1780 parenlevel--; |
| |
1781 if (parenlevel > 1) { |
| |
1782 tempstr[tempstridx++]=*ptr; |
| |
1783 } else { |
| |
1784 ptr++; |
| |
1785 } |
| |
1786 } |
| |
1787 gaim_debug_info("zephyr","tempstr parsed\n"); |
| |
1788 /* tempstr should now be a tempstridx length string containing all characters |
| |
1789 from that after the first ( to the one before the last paren ). */ |
| |
1790 /* We should have the following possible lisp strings but we don't care |
| |
1791 (tzcspew . start) (version . "something") (pid . number)*/ |
| |
1792 /* We care about 'zephyrid . "username@REALM.NAME"' and 'exposure . "SOMETHING"' */ |
| |
1793 tempstridx=0; |
| |
1794 if (!g_ascii_strncasecmp(tempstr,"zephyrid",8)) { |
| |
1795 gchar* username = g_malloc0(100); |
| |
1796 int username_idx=0; |
| |
1797 char *realm; |
| |
1798 gaim_debug_info("zephyr","zephyrid found\n"); |
| |
1799 tempstridx+=8; |
| |
1800 while(tempstr[tempstridx] !='"' && tempstridx < 20000) |
| |
1801 tempstridx++; |
| |
1802 tempstridx++; |
| |
1803 while(tempstr[tempstridx] !='"' && tempstridx < 20000) |
| |
1804 username[username_idx++]=tempstr[tempstridx++]; |
| |
1805 |
| |
1806 zephyr->username = g_strdup_printf("%s",username); |
| |
1807 if ((realm = strchr(username,'@'))) |
| |
1808 zephyr->realm = g_strdup_printf("%s",realm+1); |
| |
1809 else { |
| |
1810 realm = (gchar *)gaim_account_get_string(gc->account,"realm",""); |
| |
1811 if (!*realm) { |
| |
1812 realm = "local-realm"; |
| |
1813 } |
| |
1814 zephyr->realm = g_strdup(realm); |
| |
1815 g_strlcpy(__Zephyr_realm, (const char*)zephyr->realm, REALM_SZ-1); |
| |
1816 } |
| |
1817 /* else { |
| |
1818 zephyr->realm = g_strdup("local-realm"); |
| |
1819 }*/ |
| |
1820 |
| |
1821 g_free(username); |
| |
1822 } else { |
| |
1823 gaim_debug_info("zephyr", "something that's not zephyr id found %s\n",tempstr); |
| |
1824 } |
| |
1825 |
| |
1826 /* We don't care about anything else yet */ |
| |
1827 g_free(tempstr); |
| |
1828 break; |
| |
1829 default: |
| |
1830 gaim_debug_info("zephyr","parenlevel is not 1 or 2\n"); |
| |
1831 /* This shouldn't be happening */ |
| |
1832 break; |
| |
1833 } |
| |
1834 if (parenlevel==0) |
| |
1835 break; |
| |
1836 } /* while (ptr < bufcur) */ |
| |
1837 gaim_debug_info("zephyr", "tzc startup done\n"); |
| |
1838 free(buf); |
| |
1839 } |
| |
1840 } |
| |
1841 else if ( use_zeph02(zephyr)) { |
| |
1842 gchar* realm; |
| |
1843 z_call_s(ZInitialize(), "Couldn't initialize zephyr"); |
| |
1844 z_call_s(ZOpenPort(&(zephyr->port)), "Couldn't open port"); |
| |
1845 z_call_s(ZSetLocation((char *)zephyr->exposure), "Couldn't set location"); |
| |
1846 |
| |
1847 realm = (gchar *)gaim_account_get_string(gc->account,"realm",""); |
| |
1848 if (!*realm) { |
| |
1849 realm = ZGetRealm(); |
| |
1850 } |
| |
1851 zephyr->realm = g_strdup(realm); |
| |
1852 g_strlcpy(__Zephyr_realm, (const char*)zephyr->realm, REALM_SZ-1); |
| |
1853 zephyr->username = g_strdup(ZGetSender()); |
| |
1854 |
| |
1855 /* zephyr->realm = g_strdup(ZGetRealm()); */ |
| |
1856 gaim_debug_info("zephyr","realm: %s\n",zephyr->realm); |
| |
1857 } |
| |
1858 else { |
| |
1859 gaim_connection_error(gc,"Only ZEPH0.2 supported currently"); |
| |
1860 return; |
| |
1861 } |
| |
1862 gaim_debug_info("zephyr","does it get here\n"); |
| |
1863 gaim_debug_info("zephyr"," realm: %s username:%s\n", zephyr->realm, zephyr->username); |
| |
1864 |
| |
1865 /* For now */ |
| |
1866 zephyr->galaxy = NULL; |
| |
1867 zephyr->krbtkfile = NULL; |
| |
1868 zephyr_inithosts(zephyr); |
| |
1869 |
| |
1870 if (zephyr_subscribe_to(zephyr,"MESSAGE","PERSONAL",zephyr->username,NULL) != ZERR_NONE) { |
| |
1871 /* XXX don't translate this yet. It could be written better */ |
| |
1872 /* XXX error messages could be handled with more detail */ |
| |
1873 gaim_notify_error(account->gc, NULL, |
| |
1874 "Unable to subscribe to messages", "Unable to subscribe to initial messages"); |
| |
1875 return; |
| |
1876 } |
| |
1877 |
| |
1878 gaim_connection_set_state(gc, GAIM_CONNECTED); |
| |
1879 |
| |
1880 if (read_anyone) |
| |
1881 process_anyone(gc); |
| |
1882 if (read_zsubs) |
| |
1883 process_zsubs(zephyr); |
| |
1884 |
| |
1885 if (use_zeph02(zephyr)) { |
| |
1886 zephyr->nottimer = gaim_timeout_add(100, check_notify_zeph02, gc); |
| |
1887 } else if (use_tzc(zephyr)) { |
| |
1888 zephyr->nottimer = gaim_timeout_add(100, check_notify_tzc, gc); |
| |
1889 } |
| |
1890 zephyr->loctimer = gaim_timeout_add(20000, check_loc, gc); |
| |
1891 |
| |
1892 } |
| |
1893 |
| |
1894 static void write_zsubs(zephyr_account *zephyr) |
| |
1895 { |
| |
1896 /* Exports subscription (chat) list back to |
| |
1897 * .zephyr.subs |
| |
1898 * XXX deal with %host%, %canon%, unsubscriptions, and negative subscriptions (punts?) |
| |
1899 */ |
| |
1900 |
| |
1901 GSList *s = zephyr->subscrips; |
| |
1902 zephyr_triple *zt; |
| |
1903 FILE *fd; |
| |
1904 char *fname; |
| |
1905 |
| |
1906 char **triple; |
| |
1907 |
| |
1908 fname = g_strdup_printf("%s/.zephyr.subs", gaim_home_dir()); |
| |
1909 fd = g_fopen(fname, "w"); |
| |
1910 |
| |
1911 if (!fd) { |
| |
1912 g_free(fname); |
| |
1913 return; |
| |
1914 } |
| |
1915 |
| |
1916 while (s) { |
| |
1917 char *zclass, *zinst, *zrecip; |
| |
1918 zt = s->data; |
| |
1919 triple = g_strsplit(zt->name, ",", 3); |
| |
1920 |
| |
1921 /* deal with classes */ |
| |
1922 if (!g_ascii_strcasecmp(triple[0],zephyr->ourhost)) { |
| |
1923 zclass = g_strdup("%host%"); |
| |
1924 } else if (!g_ascii_strcasecmp(triple[0],zephyr->ourhostcanon)) { |
| |
1925 zclass = g_strdup("%canon%"); |
| |
1926 } else { |
| |
1927 zclass = g_strdup(triple[0]); |
| |
1928 } |
| |
1929 |
| |
1930 /* deal with instances */ |
| |
1931 |
| |
1932 if (!g_ascii_strcasecmp(triple[1],zephyr->ourhost)) { |
| |
1933 zinst = g_strdup("%host%"); |
| |
1934 } else if (!g_ascii_strcasecmp(triple[1],zephyr->ourhostcanon)) { |
| |
1935 zinst = g_strdup("%canon%");; |
| |
1936 } else { |
| |
1937 zinst = g_strdup(triple[1]); |
| |
1938 } |
| |
1939 |
| |
1940 /* deal with recipients */ |
| |
1941 if (triple[2] == NULL) { |
| |
1942 zrecip = g_strdup("*"); |
| |
1943 } else if (!g_ascii_strcasecmp(triple[2],"")){ |
| |
1944 zrecip = g_strdup("*"); |
| |
1945 } else if (!g_ascii_strcasecmp(triple[2], zephyr->username)) { |
| |
1946 zrecip = g_strdup("%me%"); |
| |
1947 } else { |
| |
1948 zrecip = g_strdup(triple[2]); |
| |
1949 } |
| |
1950 |
| |
1951 fprintf(fd, "%s,%s,%s\n",zclass,zinst,zrecip); |
| |
1952 |
| |
1953 g_free(zclass); |
| |
1954 g_free(zinst); |
| |
1955 g_free(zrecip); |
| |
1956 g_free(triple); |
| |
1957 s = s->next; |
| |
1958 } |
| |
1959 g_free(fname); |
| |
1960 fclose(fd); |
| |
1961 } |
| |
1962 |
| |
1963 static void write_anyone(GaimConnection *gc) |
| |
1964 { |
| |
1965 GaimBlistNode *gnode, *cnode, *bnode; |
| |
1966 GaimBuddy *b; |
| |
1967 char *fname; |
| |
1968 FILE *fd; |
| |
1969 zephyr_account* zephyr = gc->proto_data; |
| |
1970 fname = g_strdup_printf("%s/.anyone", gaim_home_dir()); |
| |
1971 fd = g_fopen(fname, "w"); |
| |
1972 if (!fd) { |
| |
1973 g_free(fname); |
| |
1974 return; |
| |
1975 } |
| |
1976 |
| |
1977 for (gnode = gaim_get_blist()->root; gnode; gnode = gnode->next) { |
| |
1978 if (!GAIM_BLIST_NODE_IS_GROUP(gnode)) |
| |
1979 continue; |
| |
1980 for (cnode = gnode->child; cnode; cnode = cnode->next) { |
| |
1981 if (!GAIM_BLIST_NODE_IS_CONTACT(cnode)) |
| |
1982 continue; |
| |
1983 for (bnode = cnode->child; bnode; bnode = bnode->next) { |
| |
1984 if (!GAIM_BLIST_NODE_IS_BUDDY(bnode)) |
| |
1985 continue; |
| |
1986 b = (GaimBuddy *) bnode; |
| |
1987 if (b->account == gc->account) { |
| |
1988 gchar *stripped_user = zephyr_strip_local_realm(zephyr,b->name); |
| |
1989 fprintf(fd, "%s\n", stripped_user); |
| |
1990 g_free(stripped_user); |
| |
1991 } |
| |
1992 } |
| |
1993 } |
| |
1994 } |
| |
1995 |
| |
1996 fclose(fd); |
| |
1997 g_free(fname); |
| |
1998 } |
| |
1999 |
| |
2000 static void zephyr_close(GaimConnection * gc) |
| |
2001 { |
| |
2002 GList *l; |
| |
2003 GSList *s; |
| |
2004 zephyr_account *zephyr = gc->proto_data; |
| |
2005 pid_t tzc_pid = zephyr->tzc_pid; |
| |
2006 |
| |
2007 l = zephyr->pending_zloc_names; |
| |
2008 while (l) { |
| |
2009 g_free((char *)l->data); |
| |
2010 l = l->next; |
| |
2011 } |
| |
2012 g_list_free(zephyr->pending_zloc_names); |
| |
2013 |
| |
2014 if (gaim_account_get_bool(gc->account, "write_anyone", FALSE)) |
| |
2015 write_anyone(gc); |
| |
2016 |
| |
2017 if (gaim_account_get_bool(gc->account, "write_zsubs", FALSE)) |
| |
2018 write_zsubs(gc->proto_data); |
| |
2019 |
| |
2020 s = zephyr->subscrips; |
| |
2021 while (s) { |
| |
2022 free_triple((zephyr_triple *) s->data); |
| |
2023 s = s->next; |
| |
2024 } |
| |
2025 g_slist_free(zephyr->subscrips); |
| |
2026 |
| |
2027 if (zephyr->nottimer) |
| |
2028 gaim_timeout_remove(zephyr->nottimer); |
| |
2029 zephyr->nottimer = 0; |
| |
2030 if (zephyr->loctimer) |
| |
2031 gaim_timeout_remove(zephyr->loctimer); |
| |
2032 zephyr->loctimer = 0; |
| |
2033 gc = NULL; |
| |
2034 if (use_zeph02(zephyr)) { |
| |
2035 z_call(ZCancelSubscriptions(0)); |
| |
2036 z_call(ZUnsetLocation()); |
| |
2037 z_call(ZClosePort()); |
| |
2038 } else { |
| |
2039 /* assume tzc */ |
| |
2040 if (kill(tzc_pid,SIGTERM) == -1) { |
| |
2041 int err=errno; |
| |
2042 if (err==EINVAL) { |
| |
2043 gaim_debug_error("zephyr","An invalid signal was specified when killing tzc\n"); |
| |
2044 } |
| |
2045 else if (err==ESRCH) { |
| |
2046 gaim_debug_error("zephyr","Tzc's pid didn't exist while killing tzc\n"); |
| |
2047 } |
| |
2048 else if (err==EPERM) { |
| |
2049 gaim_debug_error("zephyr","gaim didn't have permission to kill tzc\n"); |
| |
2050 } |
| |
2051 else { |
| |
2052 gaim_debug_error("zephyr","miscellaneous error while attempting to close tzc\n"); |
| |
2053 } |
| |
2054 } |
| |
2055 } |
| |
2056 } |
| |
2057 |
| |
2058 static int zephyr_send_message(zephyr_account *zephyr,char* zclass, char* instance, char* recipient, const char *im, |
| |
2059 const char *sig, char *opcode) ; |
| |
2060 |
| |
2061 static const char * zephyr_get_signature() |
| |
2062 { |
| |
2063 /* XXX add zephyr error reporting */ |
| |
2064 const char * sig =ZGetVariable("zwrite-signature"); |
| |
2065 if (!sig) { |
| |
2066 sig = g_get_real_name(); |
| |
2067 } |
| |
2068 return sig; |
| |
2069 } |
| |
2070 |
| |
2071 static int zephyr_chat_send(GaimConnection * gc, int id, const char *im, GaimMessageFlags flags) |
| |
2072 { |
| |
2073 zephyr_triple *zt; |
| |
2074 const char *sig; |
| |
2075 GaimConversation *gconv1; |
| |
2076 GaimConvChat *gcc; |
| |
2077 char *inst; |
| |
2078 char *recipient; |
| |
2079 zephyr_account *zephyr = gc->proto_data; |
| |
2080 |
| |
2081 zt = find_sub_by_id(gc->proto_data,id); |
| |
2082 if (!zt) |
| |
2083 /* this should never happen. */ |
| |
2084 return -EINVAL; |
| |
2085 |
| |
2086 sig = zephyr_get_signature(); |
| |
2087 |
| |
2088 gconv1 = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT, zt->name, |
| |
2089 gc->account); |
| |
2090 gcc = gaim_conversation_get_chat_data(gconv1); |
| |
2091 |
| |
2092 if (!(inst = (char *)gaim_conv_chat_get_topic(gcc))) |
| |
2093 inst = g_strdup("PERSONAL"); |
| |
2094 |
| |
2095 if (!g_ascii_strcasecmp(zt->recipient, "*")) |
| |
2096 recipient = local_zephyr_normalize(zephyr,""); |
| |
2097 else |
| |
2098 recipient = local_zephyr_normalize(zephyr,zt->recipient); |
| |
2099 |
| |
2100 zephyr_send_message(zephyr,zt->class,inst,recipient,im,sig,""); |
| |
2101 return 0; |
| |
2102 } |
| |
2103 |
| |
2104 |
| |
2105 static int zephyr_send_im(GaimConnection * gc, const char *who, const char *im, GaimMessageFlags flags) |
| |
2106 { |
| |
2107 const char *sig; |
| |
2108 zephyr_account *zephyr = gc->proto_data; |
| |
2109 if (flags & GAIM_MESSAGE_AUTO_RESP) |
| |
2110 sig = "Automated reply:"; |
| |
2111 else { |
| |
2112 sig = zephyr_get_signature(); |
| |
2113 } |
| |
2114 zephyr_send_message(zephyr,"MESSAGE","PERSONAL",local_zephyr_normalize(zephyr,who),im,sig,""); |
| |
2115 |
| |
2116 return 1; |
| |
2117 } |
| |
2118 |
| |
2119 /* Munge the outgoing zephyr so that any quotes or backslashes are |
| |
2120 escaped and do not confuse tzc: */ |
| |
2121 |
| |
2122 static char* zephyr_tzc_escape_msg(const char *message) |
| |
2123 { |
| |
2124 int pos = 0; |
| |
2125 int pos2 = 0; |
| |
2126 char *newmsg; |
| |
2127 |
| |
2128 if (message && (strlen(message) > 0)) { |
| |
2129 newmsg = g_new0(char,1+strlen(message)*2); |
| |
2130 while(pos < strlen(message)) { |
| |
2131 if (message[pos]=='\\') { |
| |
2132 newmsg[pos2]='\\'; |
| |
2133 newmsg[pos2+1]='\\'; |
| |
2134 pos2+=2; |
| |
2135 } |
| |
2136 else if (message[pos]=='"') { |
| |
2137 newmsg[pos2]='\\'; |
| |
2138 newmsg[pos2+1]='"'; |
| |
2139 pos2+=2; |
| |
2140 } |
| |
2141 else { |
| |
2142 newmsg[pos2] = message[pos]; |
| |
2143 pos2++; |
| |
2144 } |
| |
2145 pos++; |
| |
2146 } |
| |
2147 } else { |
| |
2148 newmsg = g_strdup(""); |
| |
2149 } |
| |
2150 /* fprintf(stderr,"newmsg %s message %s\n",newmsg,message); */ |
| |
2151 return newmsg; |
| |
2152 } |
| |
2153 |
| |
2154 char* zephyr_tzc_deescape_str(const char *message) |
| |
2155 { |
| |
2156 int pos = 0; |
| |
2157 int pos2 = 0; |
| |
2158 char *newmsg; |
| |
2159 |
| |
2160 if (message && (strlen(message) > 0)) { |
| |
2161 newmsg = g_new0(char,strlen(message)+1); |
| |
2162 while(pos < strlen(message)) { |
| |
2163 if (message[pos]=='\\') { |
| |
2164 pos++; |
| |
2165 } |
| |
2166 newmsg[pos2] = message[pos]; |
| |
2167 pos++;pos2++; |
| |
2168 } |
| |
2169 newmsg[pos2]='\0'; |
| |
2170 } else { |
| |
2171 newmsg = g_strdup(""); |
| |
2172 } |
| |
2173 |
| |
2174 return newmsg; |
| |
2175 } |
| |
2176 |
| |
2177 static int zephyr_send_message(zephyr_account *zephyr,char* zclass, char* instance, char* recipient, const char *im, |
| |
2178 const char *sig, char *opcode) |
| |
2179 { |
| |
2180 |
| |
2181 /* (From the tzc source) |
| |
2182 * emacs sends something of the form: |
| |
2183 * ((class . "MESSAGE") |
| |
2184 * (auth . t) |
| |
2185 * (recipients ("PERSONAL" . "bovik") ("test" . "")) |
| |
2186 * (sender . "bovik") |
| |
2187 * (message . ("Harry Bovik" "my zgram")) |
| |
2188 * ) |
| |
2189 */ |
| |
2190 char *html_buf; |
| |
2191 char *html_buf2; |
| |
2192 html_buf = html_to_zephyr(im); |
| |
2193 html_buf2 = gaim_unescape_html(html_buf); |
| |
2194 |
| |
2195 if(use_tzc(zephyr)) { |
| |
2196 char* zsendstr; |
| |
2197 /* CMU cclub tzc doesn't grok opcodes for now */ |
| |
2198 char* tzc_sig = zephyr_tzc_escape_msg(sig); |
| |
2199 char *tzc_body = zephyr_tzc_escape_msg(html_buf2); |
| |
2200 zsendstr = g_strdup_printf("((tzcfodder . send) (class . \"%s\") (auth . t) (recipients (\"%s\" . \"%s\")) (message . (\"%s\" \"%s\")) ) \n", |
| |
2201 zclass, instance, recipient, tzc_sig, tzc_body); |
| |
2202 /* fprintf(stderr,"zsendstr = %s\n",zsendstr); */ |
| |
2203 write(zephyr->totzc[ZEPHYR_FD_WRITE],zsendstr,strlen(zsendstr)); |
| |
2204 g_free(zsendstr); |
| |
2205 } else if (use_zeph02(zephyr)) { |
| |
2206 ZNotice_t notice; |
| |
2207 char *buf = g_strdup_printf("%s%c%s", sig, '\0', html_buf2); |
| |
2208 bzero((char *)¬ice, sizeof(notice)); |
| |
2209 |
| |
2210 notice.z_kind = ACKED; |
| |
2211 notice.z_port = 0; |
| |
2212 notice.z_opcode = ""; |
| |
2213 notice.z_class = zclass; |
| |
2214 notice.z_class_inst = instance; |
| |
2215 notice.z_recipient = recipient; |
| |
2216 notice.z_sender = 0; |
| |
2217 notice.z_default_format = "Class $class, Instance $instance:\n" "To: @bold($recipient) at $time $date\n" "From: @bold($1) <$sender>\n\n$2"; |
| |
2218 notice.z_message_len = strlen(html_buf2) + strlen(sig) + 2; |
| |
2219 notice.z_message = buf; |
| |
2220 notice.z_opcode = g_strdup(opcode); |
| |
2221 gaim_debug_info("zephyr","About to send notice"); |
| |
2222 if (! ZSendNotice(¬ice, ZAUTH) == ZERR_NONE) { |
| |
2223 /* XXX handle errors here */ |
| |
2224 return 0; |
| |
2225 } |
| |
2226 gaim_debug_info("zephyr","notice sent"); |
| |
2227 g_free(buf); |
| |
2228 } |
| |
2229 |
| |
2230 g_free(html_buf2); |
| |
2231 g_free(html_buf); |
| |
2232 |
| |
2233 return 1; |
| |
2234 } |
| |
2235 |
| |
2236 char *local_zephyr_normalize(zephyr_account *zephyr,const char *orig) |
| |
2237 { |
| |
2238 /* |
| |
2239 Basically the inverse of zephyr_strip_local_realm |
| |
2240 */ |
| |
2241 char* buf; |
| |
2242 |
| |
2243 if (!g_ascii_strcasecmp(orig, "")) { |
| |
2244 return g_strdup(""); |
| |
2245 } |
| |
2246 |
| |
2247 if (strchr(orig,'@')) { |
| |
2248 buf = g_strdup_printf("%s",orig); |
| |
2249 } else { |
| |
2250 buf = g_strdup_printf("%s@%s",orig,zephyr->realm); |
| |
2251 } |
| |
2252 return buf; |
| |
2253 } |
| |
2254 |
| |
2255 static void zephyr_zloc(GaimConnection *gc, const char *who) |
| |
2256 { |
| |
2257 ZAsyncLocateData_t ald; |
| |
2258 zephyr_account *zephyr = gc->proto_data; |
| |
2259 gchar* normalized_who = local_zephyr_normalize(zephyr,who); |
| |
2260 |
| |
2261 if (use_zeph02(zephyr)) { |
| |
2262 if (ZRequestLocations(normalized_who, &ald, UNACKED, ZAUTH) == ZERR_NONE) { |
| |
2263 zephyr->pending_zloc_names = g_list_append(zephyr->pending_zloc_names, |
| |
2264 g_strdup(normalized_who)); |
| |
2265 } else { |
| |
2266 /* XXX deal with errors somehow */ |
| |
2267 } |
| |
2268 } else if (use_tzc(zephyr)) { |
| |
2269 char* zlocstr = g_strdup_printf("((tzcfodder . zlocate) \"%s\")\n",normalized_who); |
| |
2270 zephyr->pending_zloc_names = g_list_append(zephyr->pending_zloc_names, g_strdup(normalized_who)); |
| |
2271 write(zephyr->totzc[ZEPHYR_FD_WRITE],zlocstr,strlen(zlocstr)); |
| |
2272 g_free(zlocstr); |
| |
2273 } |
| |
2274 } |
| |
2275 |
| |
2276 static void zephyr_set_status(GaimAccount *account, GaimStatus *status) { |
| |
2277 zephyr_account *zephyr = gaim_account_get_connection(account)->proto_data; |
| |
2278 GaimStatusPrimitive primitive = gaim_status_type_get_primitive(gaim_status_get_type(status)); |
| |
2279 |
| |
2280 if (zephyr->away) { |
| |
2281 g_free(zephyr->away); |
| |
2282 zephyr->away=NULL; |
| |
2283 } |
| |
2284 |
| |
2285 if (primitive == GAIM_STATUS_AWAY) { |
| |
2286 zephyr->away = g_strdup(gaim_status_get_attr_string(status,"message")); |
| |
2287 } |
| |
2288 else if (primitive == GAIM_STATUS_AVAILABLE) { |
| |
2289 if (use_zeph02(zephyr)) { |
| |
2290 ZSetLocation(zephyr->exposure); |
| |
2291 } |
| |
2292 else { |
| |
2293 char *zexpstr = g_strdup_printf("((tzcfodder . set-location) (hostname . \"%s\") (exposure . \"%s\"))\n",zephyr->ourhost,zephyr->exposure); |
| |
2294 write(zephyr->totzc[ZEPHYR_FD_WRITE],zexpstr,strlen(zexpstr)); |
| |
2295 g_free(zexpstr); |
| |
2296 } |
| |
2297 } |
| |
2298 else if (primitive == GAIM_STATUS_INVISIBLE) { |
| |
2299 /* XXX handle errors */ |
| |
2300 if (use_zeph02(zephyr)) { |
| |
2301 ZSetLocation(EXPOSE_OPSTAFF); |
| |
2302 } else { |
| |
2303 char *zexpstr = g_strdup_printf("((tzcfodder . set-location) (hostname . \"%s\") (exposure . \"%s\"))\n",zephyr->ourhost,EXPOSE_OPSTAFF); |
| |
2304 write(zephyr->totzc[ZEPHYR_FD_WRITE],zexpstr,strlen(zexpstr)); |
| |
2305 g_free(zexpstr); |
| |
2306 } |
| |
2307 } |
| |
2308 } |
| |
2309 |
| |
2310 static GList *zephyr_status_types(GaimAccount *account) |
| |
2311 { |
| |
2312 GaimStatusType *type; |
| |
2313 GList *types = NULL; |
| |
2314 |
| |
2315 /* zephyr has several exposures |
| |
2316 NONE (where you are hidden, and zephyrs to you are in practice silently dropped -- yes this is wrong) |
| |
2317 OPSTAFF "hidden" |
| |
2318 REALM-VISIBLE visible to people in local realm |
| |
2319 REALM-ANNOUNCED REALM-VISIBLE+ plus your logins/logouts are announced to <login,username,*> |
| |
2320 NET-VISIBLE REALM-ANNOUNCED, plus visible to people in foreign realm |
| |
2321 NET-ANNOUNCED NET-VISIBLE, plus logins/logouts are announced to <login,username,*> |
| |
2322 |
| |
2323 Online will set the user to the exposure they have in their options (defaulting to REALM-VISIBLE), |
| |
2324 Hidden, will set the user's exposure to OPSTAFF |
| |
2325 |
| |
2326 Away won't change their exposure but will set an auto away message (for IMs only) |
| |
2327 */ |
| |
2328 |
| |
2329 type = gaim_status_type_new(GAIM_STATUS_AVAILABLE, NULL, NULL, TRUE); |
| |
2330 types = g_list_append(types,type); |
| |
2331 |
| |
2332 type = gaim_status_type_new(GAIM_STATUS_INVISIBLE, NULL, NULL, TRUE); |
| |
2333 types = g_list_append(types,type); |
| |
2334 |
| |
2335 type = gaim_status_type_new_with_attrs( |
| |
2336 GAIM_STATUS_AWAY, NULL, NULL, TRUE, TRUE, FALSE, |
| |
2337 "message", _("Message"), gaim_value_new(GAIM_TYPE_STRING), |
| |
2338 NULL); |
| |
2339 types = g_list_append(types, type); |
| |
2340 |
| |
2341 type = gaim_status_type_new(GAIM_STATUS_OFFLINE, NULL, NULL, TRUE); |
| |
2342 types = g_list_append(types,type); |
| |
2343 |
| |
2344 return types; |
| |
2345 } |
| |
2346 |
| |
2347 static GList *zephyr_chat_info(GaimConnection * gc) |
| |
2348 { |
| |
2349 GList *m = NULL; |
| |
2350 struct proto_chat_entry *pce; |
| |
2351 |
| |
2352 pce = g_new0(struct proto_chat_entry, 1); |
| |
2353 |
| |
2354 pce->label = _("_Class:"); |
| |
2355 pce->identifier = "class"; |
| |
2356 m = g_list_append(m, pce); |
| |
2357 |
| |
2358 pce = g_new0(struct proto_chat_entry, 1); |
| |
2359 |
| |
2360 pce->label = _("_Instance:"); |
| |
2361 pce->identifier = "instance"; |
| |
2362 m = g_list_append(m, pce); |
| |
2363 |
| |
2364 pce = g_new0(struct proto_chat_entry, 1); |
| |
2365 |
| |
2366 pce->label = _("_Recipient:"); |
| |
2367 pce->identifier = "recipient"; |
| |
2368 m = g_list_append(m, pce); |
| |
2369 |
| |
2370 return m; |
| |
2371 } |
| |
2372 |
| |
2373 /* Called when the server notifies us a message couldn't get sent */ |
| |
2374 |
| |
2375 static void zephyr_subscribe_failed(GaimConnection *gc,char * z_class, char *z_instance, char * z_recipient, char* z_galaxy) |
| |
2376 { |
| |
2377 gchar* subscribe_failed = g_strdup_printf(_("Attempt to subscribe to %s,%s,%s failed"), z_class, z_instance,z_recipient); |
| |
2378 gaim_notify_error(gc,"", subscribe_failed, NULL); |
| |
2379 g_free(subscribe_failed); |
| |
2380 } |
| |
2381 |
| |
2382 static char *zephyr_get_chat_name(GHashTable *data) { |
| |
2383 gchar* zclass = g_hash_table_lookup(data,"class"); |
| |
2384 gchar* inst = g_hash_table_lookup(data,"instance"); |
| |
2385 gchar* recipient = g_hash_table_lookup(data, "recipient"); |
| |
2386 if (!zclass) /* This should never happen */ |
| |
2387 zclass = ""; |
| |
2388 if (!inst) |
| |
2389 inst = "*"; |
| |
2390 if (!recipient) |
| |
2391 recipient = ""; |
| |
2392 return g_strdup_printf("%s,%s,%s",zclass,inst,recipient); |
| |
2393 } |
| |
2394 |
| |
2395 |
| |
2396 static void zephyr_join_chat(GaimConnection * gc, GHashTable * data) |
| |
2397 { |
| |
2398 /* ZSubscription_t sub; */ |
| |
2399 zephyr_triple *zt1, *zt2; |
| |
2400 const char *classname; |
| |
2401 const char *instname; |
| |
2402 const char *recip; |
| |
2403 zephyr_account *zephyr=gc->proto_data; |
| |
2404 classname = g_hash_table_lookup(data, "class"); |
| |
2405 instname = g_hash_table_lookup(data, "instance"); |
| |
2406 recip = g_hash_table_lookup(data, "recipient"); |
| |
2407 |
| |
2408 |
| |
2409 if (!classname) |
| |
2410 return; |
| |
2411 |
| |
2412 if (!g_ascii_strcasecmp(classname,"%host%")) |
| |
2413 classname = g_strdup(zephyr->ourhost); |
| |
2414 if (!g_ascii_strcasecmp(classname,"%canon%")) |
| |
2415 classname = g_strdup(zephyr->ourhostcanon); |
| |
2416 |
| |
2417 if (!instname || !strlen(instname)) |
| |
2418 instname = "*"; |
| |
2419 |
| |
2420 if (!g_ascii_strcasecmp(instname,"%host%")) |
| |
2421 instname = g_strdup(zephyr->ourhost); |
| |
2422 if (!g_ascii_strcasecmp(instname,"%canon%")) |
| |
2423 instname = g_strdup(zephyr->ourhostcanon); |
| |
2424 |
| |
2425 if (!recip || (*recip == '*')) |
| |
2426 recip = ""; |
| |
2427 if (!g_ascii_strcasecmp(recip, "%me%")) |
| |
2428 recip = zephyr->username; |
| |
2429 |
| |
2430 zt1 = new_triple(gc->proto_data,classname, instname, recip); |
| |
2431 zt2 = find_sub_by_triple(gc->proto_data,zt1); |
| |
2432 if (zt2) { |
| |
2433 free_triple(zt1); |
| |
2434 if (!zt2->open) { |
| |
2435 if (!g_ascii_strcasecmp(instname,"*")) |
| |
2436 instname = "PERSONAL"; |
| |
2437 serv_got_joined_chat(gc, zt2->id, zt2->name); |
| |
2438 zephyr_chat_set_topic(gc,zt2->id,instname); |
| |
2439 zt2->open = TRUE; |
| |
2440 } |
| |
2441 return; |
| |
2442 } |
| |
2443 |
| |
2444 /* sub.zsub_class = zt1->class; |
| |
2445 sub.zsub_classinst = zt1->instance; |
| |
2446 sub.zsub_recipient = zt1->recipient; */ |
| |
2447 |
| |
2448 if (zephyr_subscribe_to(zephyr,zt1->class,zt1->instance,zt1->recipient,NULL) != ZERR_NONE) { |
| |
2449 /* XXX output better subscription information */ |
| |
2450 zephyr_subscribe_failed(gc,zt1->class,zt1->instance,zt1->recipient,NULL); |
| |
2451 free_triple(zt1); |
| |
2452 return; |
| |
2453 } |
| |
2454 |
| |
2455 zephyr->subscrips = g_slist_append(zephyr->subscrips, zt1); |
| |
2456 zt1->open = TRUE; |
| |
2457 serv_got_joined_chat(gc, zt1->id, zt1->name); |
| |
2458 if (!g_ascii_strcasecmp(instname,"*")) |
| |
2459 instname = "PERSONAL"; |
| |
2460 zephyr_chat_set_topic(gc,zt1->id,instname); |
| |
2461 } |
| |
2462 |
| |
2463 static void zephyr_chat_leave(GaimConnection * gc, int id) |
| |
2464 { |
| |
2465 zephyr_triple *zt; |
| |
2466 zephyr_account *zephyr = gc->proto_data; |
| |
2467 zt = find_sub_by_id(zephyr,id); |
| |
2468 |
| |
2469 if (zt) { |
| |
2470 zt->open = FALSE; |
| |
2471 zt->id = ++(zephyr->last_id); |
| |
2472 } |
| |
2473 } |
| |
2474 |
| |
2475 static GaimChat *zephyr_find_blist_chat(GaimAccount *account, const char *name) |
| |
2476 { |
| |
2477 GaimBlistNode *gnode, *cnode; |
| |
2478 |
| |
2479 /* XXX needs to be %host%,%canon%, and %me% clean */ |
| |
2480 for(gnode = gaim_get_blist()->root; gnode; gnode = gnode->next) { |
| |
2481 for(cnode = gnode->child; cnode; cnode = cnode->next) { |
| |
2482 GaimChat *chat = (GaimChat*)cnode; |
| |
2483 char *zclass, *inst, *recip; |
| |
2484 char** triple; |
| |
2485 if(!GAIM_BLIST_NODE_IS_CHAT(cnode)) |
| |
2486 continue; |
| |
2487 if(chat->account !=account) |
| |
2488 continue; |
| |
2489 if(!(zclass = g_hash_table_lookup(chat->components, "class"))) |
| |
2490 continue; |
| |
2491 if(!(inst = g_hash_table_lookup(chat->components, "instance"))) |
| |
2492 inst = g_strdup(""); |
| |
2493 if(!(recip = g_hash_table_lookup(chat->components, "recipient"))) |
| |
2494 recip = g_strdup(""); |
| |
2495 /* gaim_debug_info("zephyr","in zephyr_find_blist_chat name: %s\n",name?name:""); */ |
| |
2496 triple = g_strsplit(name,",",3); |
| |
2497 if (!g_ascii_strcasecmp(triple[0],zclass) && !g_ascii_strcasecmp(triple[1],inst) && !g_ascii_strcasecmp(triple[2],recip)) |
| |
2498 return chat; |
| |
2499 |
| |
2500 } |
| |
2501 } |
| |
2502 return NULL; |
| |
2503 } |
| |
2504 static const char *zephyr_list_icon(GaimAccount * a, GaimBuddy * b) |
| |
2505 { |
| |
2506 return "zephyr"; |
| |
2507 } |
| |
2508 |
| |
2509 static unsigned int zephyr_send_typing(GaimConnection *gc, const char *who, GaimTypingState state) { |
| |
2510 gchar *recipient; |
| |
2511 zephyr_account *zephyr = gc->proto_data; |
| |
2512 if (use_tzc(zephyr)) |
| |
2513 return 0; |
| |
2514 |
| |
2515 if (state == GAIM_NOT_TYPING) |
| |
2516 return 0; |
| |
2517 |
| |
2518 /* XXX We probably should care if this fails. Or maybe we don't want to */ |
| |
2519 if (!who) { |
| |
2520 gaim_debug_info("zephyr", "who is null\n"); |
| |
2521 recipient = local_zephyr_normalize(zephyr,""); |
| |
2522 } else { |
| |
2523 char *comma = strrchr(who, ','); |
| |
2524 /* Don't ping broadcast (chat) recipients */ |
| |
2525 /* The strrchr case finds a realm-stripped broadcast subscription |
| |
2526 e.g. comma is the last character in the string */ |
| |
2527 if (comma && ( (*(comma+1) == '\0') || (*(comma+1) == '@'))) |
| |
2528 return 0; |
| |
2529 |
| |
2530 recipient = local_zephyr_normalize(zephyr,who); |
| |
2531 } |
| |
2532 |
| |
2533 gaim_debug_info("zephyr","about to send typing notification to %s\n",recipient); |
| |
2534 zephyr_send_message(zephyr,"MESSAGE","PERSONAL",recipient,"","","PING"); |
| |
2535 gaim_debug_info("zephyr","sent typing notification\n"); |
| |
2536 |
| |
2537 /* |
| |
2538 * TODO: Is this correct? It means we will call |
| |
2539 * serv_send_typing(gc, who, GAIM_TYPING) once every 15 seconds |
| |
2540 * until the Gaim user stops typing. |
| |
2541 */ |
| |
2542 return ZEPHYR_TYPING_SEND_TIMEOUT; |
| |
2543 } |
| |
2544 |
| |
2545 |
| |
2546 |
| |
2547 static void zephyr_chat_set_topic(GaimConnection * gc, int id, const char *topic) |
| |
2548 { |
| |
2549 zephyr_triple *zt; |
| |
2550 GaimConversation *gconv; |
| |
2551 GaimConvChat *gcc; |
| |
2552 gchar *topic_utf8; |
| |
2553 zephyr_account* zephyr = gc->proto_data; |
| |
2554 char *sender = (char *)zephyr->username; |
| |
2555 |
| |
2556 zt = find_sub_by_id(gc->proto_data,id); |
| |
2557 /* find_sub_by_id can return NULL */ |
| |
2558 if (!zt) |
| |
2559 return; |
| |
2560 gconv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT, zt->name, |
| |
2561 gc->account); |
| |
2562 gcc = gaim_conversation_get_chat_data(gconv); |
| |
2563 |
| |
2564 topic_utf8 = zephyr_recv_convert(gc,(gchar *)topic,strlen(topic)); |
| |
2565 gaim_conv_chat_set_topic(gcc,sender,topic_utf8); |
| |
2566 g_free(topic_utf8); |
| |
2567 return; |
| |
2568 } |
| |
2569 |
| |
2570 /* commands */ |
| |
2571 |
| |
2572 static GaimCmdRet zephyr_gaim_cmd_msg(GaimConversation *conv, |
| |
2573 const char *cmd, char **args, char **error, void *data) |
| |
2574 { |
| |
2575 char *recipient; |
| |
2576 zephyr_account *zephyr = gaim_conversation_get_gc(conv)->proto_data; |
| |
2577 if (!g_ascii_strcasecmp(args[0],"*")) |
| |
2578 return GAIM_CMD_RET_FAILED; /* "*" is not a valid argument */ |
| |
2579 else |
| |
2580 recipient = local_zephyr_normalize(zephyr,args[0]); |
| |
2581 |
| |
2582 if (strlen(recipient) < 1) |
| |
2583 return GAIM_CMD_RET_FAILED; /* a null recipient is a chat message, not an IM */ |
| |
2584 |
| |
2585 if (zephyr_send_message(zephyr,"MESSAGE","PERSONAL",recipient,args[1],zephyr_get_signature(),"")) |
| |
2586 return GAIM_CMD_RET_OK; |
| |
2587 else |
| |
2588 return GAIM_CMD_RET_FAILED; |
| |
2589 } |
| |
2590 |
| |
2591 static GaimCmdRet zephyr_gaim_cmd_zlocate(GaimConversation *conv, |
| |
2592 const char *cmd, char **args, char **error, void *data) |
| |
2593 { |
| |
2594 zephyr_zloc(gaim_conversation_get_gc(conv),args[0]); |
| |
2595 return GAIM_CMD_RET_OK; |
| |
2596 } |
| |
2597 |
| |
2598 static GaimCmdRet zephyr_gaim_cmd_instance(GaimConversation *conv, |
| |
2599 const char *cmd, char **args, char **error, void *data) |
| |
2600 { |
| |
2601 /* Currently it sets the instance with leading spaces and |
| |
2602 * all. This might not be the best thing to do, though having |
| |
2603 * one word isn't ideal either. */ |
| |
2604 |
| |
2605 GaimConvChat *gcc = gaim_conversation_get_chat_data(conv); |
| |
2606 int id = gcc->id; |
| |
2607 const char* instance = args[0]; |
| |
2608 zephyr_chat_set_topic(gaim_conversation_get_gc(conv),id,instance); |
| |
2609 return GAIM_CMD_RET_OK; |
| |
2610 } |
| |
2611 |
| |
2612 static GaimCmdRet zephyr_gaim_cmd_joinchat_cir(GaimConversation *conv, |
| |
2613 const char *cmd, char **args, char **error, void *data) |
| |
2614 { |
| |
2615 /* Join a new zephyr chat */ |
| |
2616 GHashTable *triple = g_hash_table_new(NULL,NULL); |
| |
2617 g_hash_table_insert(triple,"class",args[0]); |
| |
2618 g_hash_table_insert(triple,"instance",args[1]); |
| |
2619 g_hash_table_insert(triple,"recipient",args[2]); |
| |
2620 zephyr_join_chat(gaim_conversation_get_gc(conv),triple); |
| |
2621 return GAIM_CMD_RET_OK; |
| |
2622 } |
| |
2623 |
| |
2624 static GaimCmdRet zephyr_gaim_cmd_zi(GaimConversation *conv, |
| |
2625 const char *cmd, char **args, char **error, void *data) |
| |
2626 { |
| |
2627 /* args = instance, message */ |
| |
2628 zephyr_account *zephyr = gaim_conversation_get_gc(conv)->proto_data; |
| |
2629 if ( zephyr_send_message(zephyr,"message",args[0],"",args[1],zephyr_get_signature(),"")) |
| |
2630 return GAIM_CMD_RET_OK; |
| |
2631 else |
| |
2632 return GAIM_CMD_RET_FAILED; |
| |
2633 } |
| |
2634 |
| |
2635 static GaimCmdRet zephyr_gaim_cmd_zci(GaimConversation *conv, |
| |
2636 const char *cmd, char **args, char **error, void *data) |
| |
2637 { |
| |
2638 /* args = class, instance, message */ |
| |
2639 zephyr_account *zephyr = gaim_conversation_get_gc(conv)->proto_data; |
| |
2640 if ( zephyr_send_message(zephyr,args[0],args[1],"",args[2],zephyr_get_signature(),"")) |
| |
2641 return GAIM_CMD_RET_OK; |
| |
2642 else |
| |
2643 return GAIM_CMD_RET_FAILED; |
| |
2644 } |
| |
2645 |
| |
2646 static GaimCmdRet zephyr_gaim_cmd_zcir(GaimConversation *conv, |
| |
2647 const char *cmd, char **args, char **error, void *data) |
| |
2648 { |
| |
2649 /* args = class, instance, recipient, message */ |
| |
2650 zephyr_account *zephyr = gaim_conversation_get_gc(conv)->proto_data; |
| |
2651 if ( zephyr_send_message(zephyr,args[0],args[1],args[2],args[3],zephyr_get_signature(),"")) |
| |
2652 return GAIM_CMD_RET_OK; |
| |
2653 else |
| |
2654 return GAIM_CMD_RET_FAILED; |
| |
2655 } |
| |
2656 |
| |
2657 static GaimCmdRet zephyr_gaim_cmd_zir(GaimConversation *conv, |
| |
2658 const char *cmd, char **args, char **error, void *data) |
| |
2659 { |
| |
2660 /* args = instance, recipient, message */ |
| |
2661 zephyr_account *zephyr = gaim_conversation_get_gc(conv)->proto_data; |
| |
2662 if ( zephyr_send_message(zephyr,"message",args[0],args[1],args[2],zephyr_get_signature(),"")) |
| |
2663 return GAIM_CMD_RET_OK; |
| |
2664 else |
| |
2665 return GAIM_CMD_RET_FAILED; |
| |
2666 } |
| |
2667 |
| |
2668 static GaimCmdRet zephyr_gaim_cmd_zc(GaimConversation *conv, |
| |
2669 const char *cmd, char **args, char **error, void *data) |
| |
2670 { |
| |
2671 /* args = class, message */ |
| |
2672 zephyr_account *zephyr = gaim_conversation_get_gc(conv)->proto_data; |
| |
2673 if ( zephyr_send_message(zephyr,args[0],"PERSONAL","",args[1],zephyr_get_signature(),"")) |
| |
2674 return GAIM_CMD_RET_OK; |
| |
2675 else |
| |
2676 return GAIM_CMD_RET_FAILED; |
| |
2677 } |
| |
2678 |
| |
2679 static void zephyr_register_slash_commands() |
| |
2680 { |
| |
2681 |
| |
2682 gaim_cmd_register("msg","ws", GAIM_CMD_P_PRPL, |
| |
2683 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, |
| |
2684 "prpl-zephyr", |
| |
2685 zephyr_gaim_cmd_msg, _("msg <nick> <message>: Send a private message to a user"), NULL); |
| |
2686 |
| |
2687 gaim_cmd_register("zlocate","w", GAIM_CMD_P_PRPL, |
| |
2688 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, |
| |
2689 "prpl-zephyr", |
| |
2690 zephyr_gaim_cmd_zlocate, _("zlocate <nick>: Locate user"), NULL); |
| |
2691 |
| |
2692 gaim_cmd_register("zl","w", GAIM_CMD_P_PRPL, |
| |
2693 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, |
| |
2694 "prpl-zephyr", |
| |
2695 zephyr_gaim_cmd_zlocate, _("zl <nick>: Locate user"), NULL); |
| |
2696 |
| |
2697 gaim_cmd_register("instance","s", GAIM_CMD_P_PRPL, |
| |
2698 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, |
| |
2699 "prpl-zephyr", |
| |
2700 zephyr_gaim_cmd_instance, _("instance <instance>: Set the instance to be used on this class"), NULL); |
| |
2701 |
| |
2702 gaim_cmd_register("inst","s", GAIM_CMD_P_PRPL, |
| |
2703 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, |
| |
2704 "prpl-zephyr", |
| |
2705 zephyr_gaim_cmd_instance, _("inst <instance>: Set the instance to be used on this class"), NULL); |
| |
2706 |
| |
2707 gaim_cmd_register("topic","s", GAIM_CMD_P_PRPL, |
| |
2708 GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, |
| |
2709 "prpl-zephyr", |
| |
2710 zephyr_gaim_cmd_instance, _("topic <instance>: Set the instance to be used on this class"), NULL); |
| |
2711 |
| |
2712 gaim_cmd_register("sub", "www", GAIM_CMD_P_PRPL, |
| |
2713 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, |
| |
2714 "prpl-zephyr", |
| |
2715 zephyr_gaim_cmd_joinchat_cir, |
| |
2716 _("sub <class> <instance> <recipient>: Join a new chat"), NULL); |
| |
2717 |
| |
2718 gaim_cmd_register("zi","ws", GAIM_CMD_P_PRPL, |
| |
2719 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, |
| |
2720 "prpl-zephyr", |
| |
2721 zephyr_gaim_cmd_zi, _("zi <instance>: Send a message to <message,<i>instance</i>,*>"), NULL); |
| |
2722 |
| |
2723 gaim_cmd_register("zci","wws",GAIM_CMD_P_PRPL, |
| |
2724 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, |
| |
2725 "prpl-zephyr", |
| |
2726 zephyr_gaim_cmd_zci, |
| |
2727 _("zci <class> <instance>: Send a message to <<i>class</i>,<i>instance</i>,*>"), NULL); |
| |
2728 |
| |
2729 gaim_cmd_register("zcir","wwws",GAIM_CMD_P_PRPL, |
| |
2730 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, |
| |
2731 "prpl-zephyr", |
| |
2732 zephyr_gaim_cmd_zcir, |
| |
2733 _("zcir <class> <instance> <recipient>: Send a message to <<i>class</i>,<i>instance</i>,<i>recipient</i>>"), NULL); |
| |
2734 |
| |
2735 gaim_cmd_register("zir","wws",GAIM_CMD_P_PRPL, |
| |
2736 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, |
| |
2737 "prpl-zephyr", |
| |
2738 zephyr_gaim_cmd_zir, |
| |
2739 _("zir <instance> <recipient>: Send a message to <MESSAGE,<i>instance</i>,<i>recipient</i>>"), NULL); |
| |
2740 |
| |
2741 gaim_cmd_register("zc","ws", GAIM_CMD_P_PRPL, |
| |
2742 GAIM_CMD_FLAG_IM | GAIM_CMD_FLAG_CHAT | GAIM_CMD_FLAG_PRPL_ONLY, |
| |
2743 "prpl-zephyr", |
| |
2744 zephyr_gaim_cmd_zc, _("zc <class>: Send a message to <<i>class</i>,PERSONAL,*>"), NULL); |
| |
2745 |
| |
2746 } |
| |
2747 |
| |
2748 |
| |
2749 static void |
| |
2750 zephyr_add_deny(GaimConnection *gc, const char *who) |
| |
2751 { |
| |
2752 gaim_privacy_deny_add(gc->account,who,1); |
| |
2753 } |
| |
2754 |
| |
2755 static void |
| |
2756 zephyr_remove_deny(GaimConnection *gc, const char *who) |
| |
2757 { |
| |
2758 gaim_privacy_deny_remove(gc->account,who,1); |
| |
2759 } |
| |
2760 |
| |
2761 static void |
| |
2762 zephyr_add_permit(GaimConnection *gc, const char *who) |
| |
2763 { |
| |
2764 gaim_privacy_permit_add(gc->account,who,1); |
| |
2765 } |
| |
2766 |
| |
2767 static void |
| |
2768 zephyr_remove_permit(GaimConnection *gc, const char *who) |
| |
2769 { |
| |
2770 gaim_privacy_permit_remove(gc->account,who,1); |
| |
2771 } |
| |
2772 |
| |
2773 static void |
| |
2774 zephyr_set_permit_deny(GaimConnection *gc) |
| |
2775 { |
| |
2776 /* This doesn't have to do anything, since really, we can just check account->perm_deny when deciding whether to di */ |
| |
2777 return; |
| |
2778 } |
| |
2779 static int zephyr_resubscribe(GaimConnection *gc) |
| |
2780 { |
| |
2781 /* Resubscribe to the in-memory list of subscriptions and also |
| |
2782 unsubscriptions*/ |
| |
2783 zephyr_account *zephyr = gc->proto_data; |
| |
2784 GSList *s = zephyr->subscrips; |
| |
2785 zephyr_triple *zt; |
| |
2786 while (s) { |
| |
2787 zt = s->data; |
| |
2788 /* XXX We really should care if this fails */ |
| |
2789 zephyr_subscribe_to(zephyr,zt->class,zt->instance,zt->recipient,NULL); |
| |
2790 s = s->next; |
| |
2791 } |
| |
2792 /* XXX handle unsubscriptions */ |
| |
2793 return 1; |
| |
2794 } |
| |
2795 |
| |
2796 |
| |
2797 static void zephyr_action_resubscribe(GaimPluginAction *action) |
| |
2798 { |
| |
2799 |
| |
2800 GaimConnection *gc = (GaimConnection *) action->context; |
| |
2801 zephyr_resubscribe(gc); |
| |
2802 } |
| |
2803 |
| |
2804 |
| |
2805 static void zephyr_action_get_subs_from_server(GaimPluginAction *action) |
| |
2806 { |
| |
2807 GaimConnection *gc = (GaimConnection *) action->context; |
| |
2808 zephyr_account *zephyr = gc->proto_data; |
| |
2809 gchar *title; |
| |
2810 int retval, nsubs, one,i; |
| |
2811 ZSubscription_t subs; |
| |
2812 if (use_zeph02(zephyr)) { |
| |
2813 GString* subout = g_string_new("Subscription list<br>"); |
| |
2814 |
| |
2815 title = g_strdup_printf("Server subscriptions for %s", zephyr->username); |
| |
2816 |
| |
2817 if (zephyr->port == 0) { |
| |
2818 gaim_debug_error("zephyr", "error while retrieving port"); |
| |
2819 return; |
| |
2820 } |
| |
2821 if ((retval = ZRetrieveSubscriptions(zephyr->port,&nsubs)) != ZERR_NONE) { |
| |
2822 /* XXX better error handling */ |
| |
2823 gaim_debug_error("zephyr", "error while retrieving subscriptions from server"); |
| |
2824 return; |
| |
2825 } |
| |
2826 for(i=0;i<nsubs;i++) { |
| |
2827 one = 1; |
| |
2828 if ((retval = ZGetSubscriptions(&subs,&one)) != ZERR_NONE) { |
| |
2829 /* XXX better error handling */ |
| |
2830 gaim_debug_error("zephyr", "error while retrieving individual subscription"); |
| |
2831 return; |
| |
2832 } |
| |
2833 g_string_append_printf(subout, "Class %s Instance %s Recipient %s<br>", |
| |
2834 subs.zsub_class, subs.zsub_classinst, |
| |
2835 subs.zsub_recipient); |
| |
2836 } |
| |
2837 gaim_notify_formatted(gc, title, title, NULL, subout->str, NULL, NULL); |
| |
2838 } else { |
| |
2839 /* XXX fix */ |
| |
2840 gaim_notify_error(gc,"","tzc doesn't support this action",NULL); |
| |
2841 } |
| |
2842 } |
| |
2843 |
| |
2844 |
| |
2845 static GList *zephyr_actions(GaimPlugin *plugin, gpointer context) |
| |
2846 { |
| |
2847 GList *list = NULL; |
| |
2848 GaimPluginAction *act = NULL; |
| |
2849 |
| |
2850 act = gaim_plugin_action_new(_("Resubscribe"), zephyr_action_resubscribe); |
| |
2851 list = g_list_append(list, act); |
| |
2852 |
| |
2853 act = gaim_plugin_action_new(_("Retrieve subscriptions from server"), zephyr_action_get_subs_from_server); |
| |
2854 list = g_list_append(list,act); |
| |
2855 |
| |
2856 return list; |
| |
2857 } |
| |
2858 |
| |
2859 static GaimPlugin *my_protocol = NULL; |
| |
2860 |
| |
2861 static GaimPluginProtocolInfo prpl_info = { |
| |
2862 OPT_PROTO_CHAT_TOPIC | OPT_PROTO_NO_PASSWORD, |
| |
2863 NULL, /* ??? user_splits */ |
| |
2864 NULL, /* ??? protocol_options */ |
| |
2865 NO_BUDDY_ICONS, |
| |
2866 zephyr_list_icon, |
| |
2867 NULL, /* ??? list_emblems */ |
| |
2868 NULL, /* ??? status_text */ |
| |
2869 NULL, /* ??? tooltip_text */ |
| |
2870 zephyr_status_types, /* status_types */ |
| |
2871 NULL, /* ??? blist_node_menu - probably all useful actions are already handled*/ |
| |
2872 zephyr_chat_info, /* chat_info */ |
| |
2873 NULL, /* chat_info_defaults */ |
| |
2874 zephyr_login, /* login */ |
| |
2875 zephyr_close, /* close */ |
| |
2876 zephyr_send_im, /* send_im */ |
| |
2877 NULL, /* XXX set info (Location?) */ |
| |
2878 zephyr_send_typing, /* send_typing */ |
| |
2879 zephyr_zloc, /* get_info */ |
| |
2880 zephyr_set_status, /* set_status */ |
| |
2881 NULL, /* ??? set idle */ |
| |
2882 NULL, /* change password */ |
| |
2883 NULL, /* add_buddy */ |
| |
2884 NULL, /* add_buddies */ |
| |
2885 NULL, /* remove_buddy */ |
| |
2886 NULL, /* remove_buddies */ |
| |
2887 zephyr_add_permit, /* add_permit */ |
| |
2888 zephyr_add_deny, /* add_deny */ |
| |
2889 zephyr_remove_permit, /* remove_permit */ |
| |
2890 zephyr_remove_deny, /* remove_deny */ |
| |
2891 zephyr_set_permit_deny, /* set_permit_deny */ |
| |
2892 zephyr_join_chat, /* join_chat */ |
| |
2893 NULL, /* reject_chat -- No chat invites*/ |
| |
2894 zephyr_get_chat_name, /* get_chat_name */ |
| |
2895 NULL, /* chat_invite -- No chat invites*/ |
| |
2896 zephyr_chat_leave, /* chat_leave */ |
| |
2897 NULL, /* chat_whisper -- No "whispering"*/ |
| |
2898 zephyr_chat_send, /* chat_send */ |
| |
2899 NULL, /* keepalive -- Not necessary*/ |
| |
2900 NULL, /* register_user -- Not supported*/ |
| |
2901 NULL, /* XXX get_cb_info */ |
| |
2902 NULL, /* get_cb_away */ |
| |
2903 NULL, /* alias_buddy */ |
| |
2904 NULL, /* group_buddy */ |
| |
2905 NULL, /* rename_group */ |
| |
2906 NULL, /* buddy_free */ |
| |
2907 NULL, /* convo_closed */ |
| |
2908 NULL, /* normalize */ |
| |
2909 NULL, /* XXX set_buddy_icon */ |
| |
2910 NULL, /* remove_group */ |
| |
2911 NULL, /* XXX get_cb_real_name */ |
| |
2912 zephyr_chat_set_topic, /* set_chat_topic */ |
| |
2913 zephyr_find_blist_chat, /* find_blist_chat */ |
| |
2914 NULL, /* roomlist_get_list */ |
| |
2915 NULL, /* roomlist_cancel */ |
| |
2916 NULL, /* roomlist_expand_category */ |
| |
2917 NULL, /* can_receive_file */ |
| |
2918 NULL, /* send_file */ |
| |
2919 NULL, /* new_xfer */ |
| |
2920 NULL, /* offline_message */ |
| |
2921 NULL, /* whiteboard_prpl_ops */ |
| |
2922 NULL, /* send_raw */ |
| |
2923 NULL, /* roomlist_room_serialize */ |
| |
2924 }; |
| |
2925 |
| |
2926 static GaimPluginInfo info = { |
| |
2927 GAIM_PLUGIN_MAGIC, |
| |
2928 GAIM_MAJOR_VERSION, |
| |
2929 GAIM_MINOR_VERSION, |
| |
2930 GAIM_PLUGIN_PROTOCOL, /**< type */ |
| |
2931 NULL, /**< ui_requirement */ |
| |
2932 0, /**< flags */ |
| |
2933 NULL, /**< dependencies */ |
| |
2934 GAIM_PRIORITY_DEFAULT, /**< priority */ |
| |
2935 |
| |
2936 "prpl-zephyr", /**< id */ |
| |
2937 "Zephyr", /**< name */ |
| |
2938 VERSION, /**< version */ |
| |
2939 /** summary */ |
| |
2940 N_("Zephyr Protocol Plugin"), |
| |
2941 /** description */ |
| |
2942 N_("Zephyr Protocol Plugin"), |
| |
2943 NULL, /**< author */ |
| |
2944 GAIM_WEBSITE, /**< homepage */ |
| |
2945 |
| |
2946 NULL, /**< load */ |
| |
2947 NULL, /**< unload */ |
| |
2948 NULL, /**< destroy */ |
| |
2949 |
| |
2950 NULL, /**< ui_info */ |
| |
2951 &prpl_info, /**< extra_info */ |
| |
2952 NULL, |
| |
2953 zephyr_actions, |
| |
2954 }; |
| |
2955 |
| |
2956 static void init_plugin(GaimPlugin * plugin) |
| |
2957 { |
| |
2958 GaimAccountOption *option; |
| |
2959 char *tmp = get_exposure_level(); |
| |
2960 |
| |
2961 option = gaim_account_option_bool_new(_("Use tzc"), "use_tzc", FALSE); |
| |
2962 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); |
| |
2963 |
| |
2964 option = gaim_account_option_string_new(_("tzc command"), "tzc_command", "/usr/bin/tzc -e %s"); |
| |
2965 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); |
| |
2966 |
| |
2967 option = gaim_account_option_bool_new(_("Export to .anyone"), "write_anyone", FALSE); |
| |
2968 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); |
| |
2969 |
| |
2970 option = gaim_account_option_bool_new(_("Export to .zephyr.subs"), "write_zsubs", FALSE); |
| |
2971 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); |
| |
2972 |
| |
2973 option = gaim_account_option_bool_new(_("Import from .anyone"), "read_anyone", TRUE); |
| |
2974 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); |
| |
2975 |
| |
2976 option = gaim_account_option_bool_new(_("Import from .zephyr.subs"), "read_zsubs", TRUE); |
| |
2977 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); |
| |
2978 |
| |
2979 option = gaim_account_option_string_new(_("Realm"), "realm", ""); |
| |
2980 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); |
| |
2981 |
| |
2982 option = gaim_account_option_string_new(_("Exposure"), "exposure_level", tmp?tmp: EXPOSE_REALMVIS); |
| |
2983 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); |
| |
2984 |
| |
2985 option = gaim_account_option_string_new(_("Encoding"), "encoding", ZEPHYR_FALLBACK_CHARSET); |
| |
2986 prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); |
| |
2987 |
| |
2988 my_protocol = plugin; |
| |
2989 zephyr_register_slash_commands(); |
| |
2990 } |
| |
2991 |
| |
2992 GAIM_INIT_PLUGIN(zephyr, init_plugin, info); |