| |
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; 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 * This program is free software; you can redistribute it and/or modify |
| |
11 * it under the terms of the GNU General Public License as published by |
| |
12 * the Free Software Foundation; either version 2 of the License, or |
| |
13 * (at your option) any later version. |
| |
14 * |
| |
15 * This program is distributed in the hope that it will be useful, |
| |
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| |
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| |
18 * GNU General Public License for more details. |
| |
19 * |
| |
20 * You should have received a copy of the GNU General Public License |
| |
21 * along with this program; if not, write to the Free Software |
| |
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| |
23 * |
| |
24 */ |
| |
25 |
| |
26 #ifdef HAVE_CONFIG_H |
| |
27 #include "config.h" |
| |
28 #endif |
| |
29 |
| |
30 #include <gtk/gtk.h> |
| |
31 #include <string.h> |
| |
32 #include "gaim.h" |
| |
33 #include "prpl.h" |
| |
34 #include "zephyr/zephyr.h" |
| |
35 |
| |
36 char *name() |
| |
37 { |
| |
38 return "Zephyr"; |
| |
39 } |
| |
40 |
| |
41 char *description() |
| |
42 { |
| |
43 return "Allows gaim to use the Zephyr protocol"; |
| |
44 } |
| |
45 |
| |
46 static char *zephyr_name() |
| |
47 { |
| |
48 return "Zephyr"; |
| |
49 } |
| |
50 |
| |
51 #define z_call(func) if (func != ZERR_NONE)\ |
| |
52 return; |
| |
53 #define z_call_r(func) if (func != ZERR_NONE)\ |
| |
54 return TRUE; |
| |
55 #define z_call_s(func, err) if (func != ZERR_NONE) {\ |
| |
56 hide_login_progress(zgc, err);\ |
| |
57 signoff(zgc);\ |
| |
58 return;\ |
| |
59 } |
| |
60 |
| |
61 /* this is so bad, and if Zephyr weren't so fucked up to begin with I |
| |
62 * wouldn't do this. but it is so i will. */ |
| |
63 static guint32 nottimer = 0; |
| |
64 static guint32 loctimer = 0; |
| |
65 struct gaim_connection *zgc = NULL; |
| |
66 |
| |
67 /* just for debugging |
| |
68 static void handle_unknown(ZNotice_t notice) |
| |
69 { |
| |
70 g_print("z_packet: %s\n", notice.z_packet); |
| |
71 g_print("z_version: %s\n", notice.z_version); |
| |
72 g_print("z_kind: %d\n", notice.z_kind); |
| |
73 g_print("z_class: %s\n", notice.z_class); |
| |
74 g_print("z_class_inst: %s\n", notice.z_class_inst); |
| |
75 g_print("z_opcode: %s\n", notice.z_opcode); |
| |
76 g_print("z_sender: %s\n", notice.z_sender); |
| |
77 g_print("z_recipient: %s\n", notice.z_recipient); |
| |
78 g_print("z_message: %s\n", notice.z_message); |
| |
79 g_print("z_message_len: %d\n", notice.z_message_len); |
| |
80 g_print("\n"); |
| |
81 } |
| |
82 */ |
| |
83 |
| |
84 static void handle_message(ZNotice_t notice, struct sockaddr_in from) |
| |
85 { |
| |
86 if (!g_strcasecmp(notice.z_class, LOGIN_CLASS)) { |
| |
87 /* well, we'll be updating in 2 seconds anyway, might as well ignore this. */ |
| |
88 } else if (!g_strcasecmp(notice.z_class, LOCATE_CLASS)) { |
| |
89 if (!g_strcasecmp(notice.z_opcode, LOCATE_LOCATE)) { |
| |
90 int nlocs; |
| |
91 char *user; |
| |
92 struct buddy *b; |
| |
93 |
| |
94 if (ZParseLocations(¬ice, NULL, &nlocs, &user) != ZERR_NONE) |
| |
95 return; |
| |
96 if ((b = find_buddy(zgc, user)) == NULL) { |
| |
97 char *e = strchr(user, '@'); |
| |
98 if (e) *e = '\0'; |
| |
99 b = find_buddy(zgc, user); |
| |
100 } |
| |
101 if (!b) { |
| |
102 free(user); |
| |
103 return; |
| |
104 } |
| |
105 serv_got_update(zgc, b->name, nlocs, 0, 0, 0, 0, 0); |
| |
106 |
| |
107 free(user); |
| |
108 } |
| |
109 } else if (!g_strcasecmp(notice.z_class, "MESSAGE")) { |
| |
110 char buf[BUF_LONG]; |
| |
111 char *ptr = notice.z_message + strlen(notice.z_message) + 1; |
| |
112 int len = notice.z_message_len - (ptr - notice.z_message); |
| |
113 if (len > 0) { |
| |
114 g_snprintf(buf, len + 1, "%s", ptr); |
| |
115 g_strchomp(buf); |
| |
116 serv_got_im(zgc, notice.z_sender, buf, 0); |
| |
117 } |
| |
118 } else { |
| |
119 /* yes. */ |
| |
120 } |
| |
121 } |
| |
122 |
| |
123 static gint check_notify(gpointer data) |
| |
124 { |
| |
125 while (ZPending()) { |
| |
126 ZNotice_t notice; |
| |
127 struct sockaddr_in from; |
| |
128 z_call_r(ZReceiveNotice(¬ice, &from)); |
| |
129 |
| |
130 switch (notice.z_kind) { |
| |
131 case UNSAFE: |
| |
132 case UNACKED: |
| |
133 case ACKED: |
| |
134 handle_message(notice, from); |
| |
135 break; |
| |
136 default: |
| |
137 /* we'll just ignore things for now */ |
| |
138 debug_printf("ZEPHYR: Unhandled Notice\n"); |
| |
139 break; |
| |
140 } |
| |
141 |
| |
142 ZFreeNotice(¬ice); |
| |
143 } |
| |
144 |
| |
145 return TRUE; |
| |
146 } |
| |
147 |
| |
148 static gint check_loc(gpointer data) |
| |
149 { |
| |
150 GSList *gr, *m; |
| |
151 ZAsyncLocateData_t ald; |
| |
152 |
| |
153 ald.user = NULL; |
| |
154 memset(&(ald.uid), 0, sizeof(ZUnique_Id_t)); |
| |
155 ald.version = NULL; |
| |
156 |
| |
157 gr = zgc->groups; |
| |
158 while (gr) { |
| |
159 struct group *g = gr->data; |
| |
160 m = g->members; |
| |
161 while (m) { |
| |
162 struct buddy *b = m->data; |
| |
163 char *chk; |
| |
164 if (!strchr(b->name, '@')) |
| |
165 chk = g_strdup_printf("%s@%s", b->name, ZGetRealm()); |
| |
166 else |
| |
167 chk = g_strdup(b->name); |
| |
168 /* doesn't matter if this fails or not; we'll just move on to the next one */ |
| |
169 ZRequestLocations(chk, &ald, UNACKED, ZAUTH); |
| |
170 g_free(chk); |
| |
171 m = m->next; |
| |
172 } |
| |
173 gr = gr->next; |
| |
174 } |
| |
175 |
| |
176 return TRUE; |
| |
177 } |
| |
178 |
| |
179 static char *get_exposure_level() |
| |
180 { |
| |
181 char *exposure = ZGetVariable("exposure"); |
| |
182 |
| |
183 if (!exposure) |
| |
184 return EXPOSE_REALMVIS; |
| |
185 if (!g_strcasecmp(exposure, EXPOSE_NONE)) |
| |
186 return EXPOSE_NONE; |
| |
187 if (!g_strcasecmp(exposure, EXPOSE_OPSTAFF)) |
| |
188 return EXPOSE_OPSTAFF; |
| |
189 if (!g_strcasecmp(exposure, EXPOSE_REALMANN)) |
| |
190 return EXPOSE_REALMANN; |
| |
191 if (!g_strcasecmp(exposure, EXPOSE_NETVIS)) |
| |
192 return EXPOSE_NETVIS; |
| |
193 if (!g_strcasecmp(exposure, EXPOSE_NETANN)) |
| |
194 return EXPOSE_NETANN; |
| |
195 return EXPOSE_REALMVIS; |
| |
196 } |
| |
197 |
| |
198 static void strip_comments(char *str) |
| |
199 { |
| |
200 char *tmp = strchr(str, '#'); |
| |
201 if (tmp) |
| |
202 *tmp = '\0'; |
| |
203 g_strchug(str); |
| |
204 g_strchomp(str); |
| |
205 } |
| |
206 |
| |
207 static void process_anyone() |
| |
208 { |
| |
209 FILE *fd; |
| |
210 gchar buff[BUFSIZ], *filename; |
| |
211 |
| |
212 filename = g_strconcat(g_get_home_dir(), "/.anyone", NULL); |
| |
213 if ((fd = fopen(filename, "r")) != NULL) { |
| |
214 while (fgets(buff, BUFSIZ, fd)) { |
| |
215 strip_comments(buff); |
| |
216 if (buff[0]) |
| |
217 add_buddy(zgc, "Anyone", buff, buff); |
| |
218 } |
| |
219 fclose(fd); |
| |
220 } |
| |
221 g_free(filename); |
| |
222 } |
| |
223 |
| |
224 static void zephyr_login(struct aim_user *user) |
| |
225 { |
| |
226 ZSubscription_t sub; |
| |
227 |
| |
228 if (zgc) { |
| |
229 do_error_dialog("Already logged in with Zephyr", "Zephyr"); |
| |
230 return; |
| |
231 } |
| |
232 |
| |
233 zgc = new_gaim_conn(user); |
| |
234 |
| |
235 z_call_s(ZInitialize(), "Couldn't initialize zephyr"); |
| |
236 z_call_s(ZOpenPort(NULL), "Couldn't open port"); |
| |
237 z_call_s(ZSetLocation(get_exposure_level()), "Couldn't set location"); |
| |
238 |
| |
239 sub.zsub_class = "MESSAGE"; |
| |
240 sub.zsub_classinst = "PERSONAL"; |
| |
241 sub.zsub_recipient = ZGetSender(); |
| |
242 |
| |
243 /* we don't care if this fails. i'm lying right now. */ |
| |
244 ZSubscribeTo(&sub, 1, 0); |
| |
245 |
| |
246 account_online(zgc); |
| |
247 serv_finish_login(zgc); |
| |
248 |
| |
249 if (bud_list_cache_exists(zgc)) |
| |
250 do_import(NULL, zgc); |
| |
251 process_anyone(); |
| |
252 /* should also process .zephyr.subs */ |
| |
253 |
| |
254 nottimer = gtk_timeout_add(100, check_notify, NULL); |
| |
255 loctimer = gtk_timeout_add(2000, check_loc, NULL); |
| |
256 } |
| |
257 |
| |
258 static void zephyr_close(struct gaim_connection *gc) |
| |
259 { |
| |
260 /* should probably write .anyone, but eh. we all use gaim exclusively, right? :-P */ |
| |
261 if (nottimer) |
| |
262 gtk_timeout_remove(nottimer); |
| |
263 nottimer = 0; |
| |
264 if (loctimer) |
| |
265 gtk_timeout_remove(loctimer); |
| |
266 loctimer = 0; |
| |
267 zgc = NULL; |
| |
268 z_call(ZCancelSubscriptions(0)); |
| |
269 z_call(ZUnsetLocation()); |
| |
270 z_call(ZClosePort()); |
| |
271 } |
| |
272 |
| |
273 static void zephyr_add_buddy(struct gaim_connection *gc, char *buddy) { } |
| |
274 static void zephyr_remove_buddy(struct gaim_connection *gc, char *buddy) { } |
| |
275 |
| |
276 static void zephyr_send_im(struct gaim_connection *gc, char *who, char *im, int away) { |
| |
277 ZNotice_t notice; |
| |
278 |
| |
279 bzero((char *)¬ice, sizeof(notice)); |
| |
280 notice.z_kind = ACKED; |
| |
281 notice.z_port = 0; |
| |
282 notice.z_opcode = ""; |
| |
283 notice.z_class = "MESSAGE"; |
| |
284 notice.z_class_inst = "PERSONAL"; |
| |
285 notice.z_sender = 0; |
| |
286 notice.z_recipient = who; |
| |
287 notice.z_default_format = |
| |
288 "Class $class, Instance $instance:\nTo: @bold($recipient) at $time $date\n$message"; |
| |
289 notice.z_message_len = strlen(im) + 1; |
| |
290 notice.z_message = im; |
| |
291 ZSendNotice(¬ice, ZAUTH); |
| |
292 } |
| |
293 |
| |
294 static struct prpl *my_protocol = NULL; |
| |
295 |
| |
296 void zephyr_init(struct prpl *ret) |
| |
297 { |
| |
298 ret->protocol = PROTO_ZEPHYR; |
| |
299 ret->name = zephyr_name; |
| |
300 ret->login = zephyr_login; |
| |
301 ret->close = zephyr_close; |
| |
302 ret->add_buddy = zephyr_add_buddy; |
| |
303 ret->remove_buddy = zephyr_remove_buddy; |
| |
304 ret->send_im = zephyr_send_im; |
| |
305 |
| |
306 my_protocol = ret; |
| |
307 } |
| |
308 |
| |
309 char *gaim_plugin_init(GModule *handle) |
| |
310 { |
| |
311 load_protocol(zephyr_init, sizeof(struct prpl)); |
| |
312 return NULL; |
| |
313 } |
| |
314 |
| |
315 void gaim_plugin_remove() |
| |
316 { |
| |
317 struct prpl *p = find_prpl(PROTO_ZEPHYR); |
| |
318 if (p == my_protocol) |
| |
319 unload_protocol(p); |
| |
320 } |