1700
|
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 }
|