comparison src/toc.c @ 1106:5bc8fdacd2cb

[gaim-migrate @ 1116] lots of changes. buddy.c: just in general tried to get things to work better. moving things in the edit list window and signing off should be handled better in the main buddy list window (watch out for flashes). gaim.h: removed toc-specific things and moved them to toc.c and rvous.c as needed. gtkhtml.c: possible fix for AOL 6.0 problems (I wasn't able to reproduce the problem before or after the fix, but i fixed what i think might have been causing the problem). multi.c: moved LOGIN_STEPS from gaim.h here and actually use it now oscar.c: moved an oscar-specific struct definition from gaim.h here and also handle problems better perl.c: fix for stupid problem rvous.c: first pass at attempt to be able to remove toc.c and rvous.c (though this will never happen; gaim will support toc as long as aol does) without cruft. gaim is now only dependent on toc.c and rvous.c for toc_build_config and parse_toc_buddy_list, which gaim needs to save and read its buddy list. toc.c: rewrote the signin process so that the read()'s won't block. it's not actually a non-blocking read; it's just that it won't ever get to the read until there's data to be read (thanks to the gdk_input watcher). this means the cancel button should work after it's connected, but it's still not a non-blocking connect. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Mon, 20 Nov 2000 07:24:18 +0000
parents f168625b63fe
children 3f56704a09bd
comparison
equal deleted inserted replaced
1105:c964df5b2a84 1106:5bc8fdacd2cb
45 #include "pixmaps/aol_icon.xpm" 45 #include "pixmaps/aol_icon.xpm"
46 #include "pixmaps/away_icon.xpm" 46 #include "pixmaps/away_icon.xpm"
47 #include "pixmaps/dt_icon.xpm" 47 #include "pixmaps/dt_icon.xpm"
48 #include "pixmaps/free_icon.xpm" 48 #include "pixmaps/free_icon.xpm"
49 49
50 #define REVISION "gaim:$Revision: 1110 $" 50 #define REVISION "gaim:$Revision: 1116 $"
51
52 #define TYPE_SIGNON 1
53 #define TYPE_DATA 2
54 #define TYPE_ERROR 3
55 #define TYPE_SIGNOFF 4
56 #define TYPE_KEEPALIVE 5
57
58 #define FLAPON "FLAPON\r\n\r\n"
59 #define ROAST "Tic/Toc"
60
61 #define TOC_HOST "toc.oscar.aol.com"
62 #define TOC_PORT 9898
63 #define AUTH_HOST "login.oscar.aol.com"
64 #define AUTH_PORT 5190
65 #define LANGUAGE "english"
66
67 #define STATE_OFFLINE 0
68 #define STATE_FLAPON 1
69 #define STATE_SIGNON_REQUEST 2
70 #define STATE_ONLINE 3
71 #define STATE_PAUSE 4
51 72
52 struct toc_data { 73 struct toc_data {
53 int toc_fd; 74 int toc_fd;
54 int seqno; 75 int seqno;
55 int state; 76 int state;
56 }; 77 };
57 78
58 79 struct sflap_hdr {
59 static unsigned int peer_ver=0; 80 unsigned char ast;
60 #ifdef _WIN32 81 unsigned char type;
61 static int win32_r; 82 unsigned short seqno;
62 #endif 83 unsigned short len;
63 84 };
64 static int toc_signon(struct gaim_connection *); 85
86 struct signon {
87 unsigned int ver;
88 unsigned short tag;
89 unsigned short namelen;
90 char username[80];
91 };
65 92
66 /* constants to identify proto_opts */ 93 /* constants to identify proto_opts */
67 #define USEROPT_AUTH 0 94 #define USEROPT_AUTH 0
68 #define USEROPT_AUTHPORT 1 95 #define USEROPT_AUTHPORT 1
69 #define USEROPT_SOCKSHOST 2 96 #define USEROPT_SOCKSHOST 2
70 #define USEROPT_SOCKSPORT 3 97 #define USEROPT_SOCKSPORT 3
71 #define USEROPT_PROXYTYPE 4 98 #define USEROPT_PROXYTYPE 4
72 99
100 static void toc_callback(gpointer, gint, GdkInputCondition);
101 static unsigned char *roast_password(char *);
102
73 /* ok. this function used to take username/password, and return 0 on success. 103 /* ok. this function used to take username/password, and return 0 on success.
74 * now, it takes username/password, and returns NULL on error or a new gaim_connection 104 * now, it takes username/password, and returns NULL on error or a new gaim_connection
75 * on success. */ 105 * on success. */
76 void toc_login(struct aim_user *user) 106 static void toc_login(struct aim_user *user) {
77 {
78 char *config;
79 struct gaim_connection *gc; 107 struct gaim_connection *gc;
80 struct toc_data *tdt; 108 struct toc_data *tdt;
81 char buf[80]; 109 char buf[80];
82 char buf2[2048];
83 110
84 gc = new_gaim_conn(user); 111 gc = new_gaim_conn(user);
85 gc->proto_data = tdt = g_new0(struct toc_data, 1); 112 gc->proto_data = tdt = g_new0(struct toc_data, 1);
86 113
87 g_snprintf(buf, sizeof(buf), "Looking up %s", 114 g_snprintf(buf, sizeof buf, "Lookin up %s",
88 user->proto_opt[USEROPT_AUTH][0] ? user->proto_opt[USEROPT_AUTH] : TOC_HOST); 115 user->proto_opt[USEROPT_AUTH][0] ? user->proto_opt[USEROPT_AUTH] : TOC_HOST);
116 /* this is such a hack */
89 set_login_progress(gc, 1, buf); 117 set_login_progress(gc, 1, buf);
90 while (gtk_events_pending()) 118 while (gtk_events_pending())
91 gtk_main_iteration(); 119 gtk_main_iteration();
92 if (!g_slist_find(connections, gc)) 120 if (!g_slist_find(connections, gc))
93 return; 121 return;
94 122
95 tdt->toc_fd = proxy_connect( 123 tdt->toc_fd = proxy_connect(
96 user->proto_opt[USEROPT_AUTH][0] ? user->proto_opt[USEROPT_AUTH] : TOC_HOST, 124 user->proto_opt[USEROPT_AUTH][0] ? user->proto_opt[USEROPT_AUTH] : TOC_HOST,
97 user->proto_opt[USEROPT_AUTHPORT][0] ? atoi(user->proto_opt[USEROPT_AUTHPORT]) : TOC_PORT, 125 user->proto_opt[USEROPT_AUTHPORT][0] ? atoi(user->proto_opt[USEROPT_AUTHPORT]):TOC_PORT,
98 user->proto_opt[USEROPT_SOCKSHOST], atoi(user->proto_opt[USEROPT_SOCKSPORT]), 126 user->proto_opt[USEROPT_SOCKSHOST], atoi(user->proto_opt[USEROPT_SOCKSPORT]),
99 atoi(user->proto_opt[USEROPT_PROXYTYPE])); 127 atoi(user->proto_opt[USEROPT_PROXYTYPE]));
100 128
101 if (tdt->toc_fd < 0) { 129 debug_printf("* Client connects to TOC\n");
130 if (tdt->toc_fd < 0) {
102 g_snprintf(buf, sizeof(buf), "Connect to %s failed", 131 g_snprintf(buf, sizeof(buf), "Connect to %s failed",
103 user->proto_opt[USEROPT_AUTH]); 132 user->proto_opt[USEROPT_AUTH]);
104 hide_login_progress(gc, buf); 133 hide_login_progress(gc, buf);
105 serv_close(gc); 134 signoff(gc);
106 return; 135 return;
107 } 136 }
137
138 debug_printf("* Client sends \"FLAPON\\r\\n\\r\\n\"\n");
139 if (write(tdt->toc_fd, FLAPON, strlen(FLAPON)) < 0) {
140 hide_login_progress(gc, "Disconnected.");
141 signoff(gc);
142 return;
143 }
144 tdt->state = STATE_FLAPON;
145
146 /* i know a lot of people like to look at gaim to see how TOC works. so i'll comment
147 * on what this does. it's really simple. when there's data ready to be read from the
148 * toc_fd file descriptor, toc_callback is called, with gc passed as its data arg. */
149 gc->inpa = gdk_input_add(tdt->toc_fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, toc_callback, gc);
108 150
109 g_snprintf(buf, sizeof(buf), "Signon: %s", gc->username); 151 g_snprintf(buf, sizeof(buf), "Signon: %s", gc->username);
110 set_login_progress(gc, 3, buf); 152 set_login_progress(gc, 2, buf);
111 while (gtk_events_pending()) 153 }
112 gtk_main_iteration(); 154
113 if (!g_slist_find(connections, gc)) 155 static void toc_set_config(struct gaim_connection *gc) {
114 return; 156 char buf[MSG_LEN], snd[MSG_LEN];
115 157 toc_build_config(gc, buf, MSG_LEN, FALSE);
116 if (toc_signon(gc) < 0) { 158 g_snprintf(snd, MSG_LEN, "toc_set_config \"%s\"", buf);
117 hide_login_progress(gc, "Disconnected."); 159 sflap_send(gc, snd, -1, TYPE_DATA);
118 serv_close(gc); 160 }
119 return; 161
120 } 162 static void toc_close(struct gaim_connection *gc) {
121 163 toc_set_config(gc);
122 g_snprintf(buf, sizeof(buf), "Waiting for reply..."); 164 if (gc->inpa > 0)
123 set_login_progress(gc, 4, buf);
124 while (gtk_events_pending())
125 gtk_main_iteration();
126 if (!g_slist_find(connections, gc))
127 return;
128 if (toc_wait_signon(gc) < 0) {
129 hide_login_progress(gc, "Authentication Failed");
130 serv_close(gc);
131 return;
132 }
133
134 gc->options = user->options;
135 save_prefs();
136
137 g_snprintf(buf, sizeof(buf), "Retrieving config...");
138 set_login_progress(gc, 5, buf);
139 while (gtk_events_pending())
140 gtk_main_iteration();
141 if (!g_slist_find(connections, gc))
142 return;
143
144 account_online(gc);
145 serv_finish_login(gc);
146
147 config = toc_wait_config(gc);
148 tdt->state = STATE_ONLINE;
149
150 if (config != NULL)
151 parse_toc_buddy_list(gc, config, 0);
152 else
153 do_import(0, gc);
154
155 g_snprintf(buf2, sizeof(buf2), "toc_init_done");
156 sflap_send(gc, buf2, -1, TYPE_DATA);
157
158 g_snprintf(buf2, sizeof(buf2), "toc_set_caps %s %s %s %s %s",
159 FILE_SEND_UID, FILE_GET_UID, B_ICON_UID, IMAGE_UID,
160 VOICE_UID);
161 sflap_send(gc, buf2, -1, TYPE_DATA);
162
163 if (gc->keepalive < 0)
164 update_keepalive(gc, gc->options & OPT_USR_KEEPALV);
165 }
166
167 void toc_close(struct gaim_connection *gc)
168 {
169 if (gc->protocol != PROTO_TOC) return; /* how did this happen? */
170 if (gc->inpa > 0)
171 gdk_input_remove(gc->inpa); 165 gdk_input_remove(gc->inpa);
172 gc->inpa = -1; 166 gc->inpa = -1;
173 close(((struct toc_data *)gc->proto_data)->toc_fd); 167 close(((struct toc_data *)gc->proto_data)->toc_fd);
174 } 168 }
175 169
176 unsigned char *roast_password(char *pass) 170 int sflap_send(struct gaim_connection *gc, char *buf, int olen, int type) {
177 {
178 /* Trivial "encryption" */
179 static char rp[256];
180 static char *roast = ROAST;
181 int pos=2;
182 int x;
183 strcpy(rp, "0x");
184 for (x=0;(x<150) && pass[x]; x++)
185 pos+=sprintf(&rp[pos],"%02x", pass[x] ^ roast[x % strlen(roast)]);
186 rp[pos]='\0';
187 return rp;
188 }
189
190
191 char *print_header(void *hdr_v)
192 {
193 static char s[80];
194 struct sflap_hdr *hdr = (struct sflap_hdr *)hdr_v;
195 g_snprintf(s,sizeof(s), "[ ast: %c, type: %d, seqno: %d, len: %d ]",
196 hdr->ast, hdr->type, ntohs(hdr->seqno), ntohs(hdr->len));
197 return s;
198 }
199
200 void print_buffer(char *buf, int len)
201 {
202 #if 0
203 int x;
204 printf("[ ");
205 for (x=0;x<len;x++)
206 printf("%d ", buf[x]);
207 printf("]\n");
208 printf("[ ");
209 for (x=0;x<len;x++)
210 printf("%c ", buf[x]);
211 printf("]\n");
212 #endif
213 }
214
215 int sflap_send(struct gaim_connection *gc, char *buf, int olen, int type)
216 {
217 int len; 171 int len;
218 int slen=0; 172 int slen=0;
219 struct sflap_hdr hdr; 173 struct sflap_hdr hdr;
220 char obuf[MSG_LEN]; 174 char obuf[MSG_LEN];
221 struct toc_data *tdt = (struct toc_data *)gc->proto_data; 175 struct toc_data *tdt = (struct toc_data *)gc->proto_data;
222 176
177 if (tdt->state == STATE_PAUSE)
178 /* TOC has given us the PAUSE message; sending could cause a disconnect
179 * so we just return here like everything went through fine */
180 return 0;
181
223 /* One _last_ 2048 check here! This shouldn't ever 182 /* One _last_ 2048 check here! This shouldn't ever
224 * get hit though, hopefully. If it gets hit on an IM 183 * get hit though, hopefully. If it gets hit on an IM
225 * It'll lose the last " and the message won't go through, 184 * It'll lose the last " and the message won't go through,
226 * but this'll stop a segfault. */ 185 * but this'll stop a segfault. */
227 if (strlen(buf) > (MSG_LEN - sizeof(hdr))) { 186 if (strlen(buf) > (MSG_LEN - sizeof(hdr))) {
187 debug_printf("message too long, truncating\n");
228 buf[MSG_LEN - sizeof(hdr) - 3] = '"'; 188 buf[MSG_LEN - sizeof(hdr) - 3] = '"';
229 buf[MSG_LEN - sizeof(hdr) - 2] = '\0'; 189 buf[MSG_LEN - sizeof(hdr) - 2] = '\0';
230 } 190 }
231 191
232 debug_printf("%s [Len %d]\n", buf, strlen(buf));
233
234 if (olen < 0) 192 if (olen < 0)
235 len = escape_message(buf); 193 len = escape_message(buf);
236 else 194 else
237 len = olen; 195 len = olen;
238 hdr.ast = '*'; 196 hdr.ast = '*';
239 hdr.type = type; 197 hdr.type = type;
240 hdr.seqno = htons(tdt->seqno++ & 0xffff); 198 hdr.seqno = htons(tdt->seqno++ & 0xffff);
241 hdr.len = htons(len + (type == TYPE_SIGNON ? 0 : 1)); 199 hdr.len = htons(len + (type == TYPE_SIGNON ? 0 : 1));
242
243 sprintf(debug_buff,"Escaped message is '%s'\n",buf);
244 debug_print(debug_buff);
245 200
246 memcpy(obuf, &hdr, sizeof(hdr)); 201 memcpy(obuf, &hdr, sizeof(hdr));
247 slen += sizeof(hdr); 202 slen += sizeof(hdr);
248 memcpy(&obuf[slen], buf, len); 203 memcpy(&obuf[slen], buf, len);
249 slen += len; 204 slen += len;
250 if (type != TYPE_SIGNON) { 205 if (type != TYPE_SIGNON) {
251 obuf[slen]='\0'; 206 obuf[slen]='\0';
252 slen += 1; 207 slen += 1;
253 } 208 }
254 print_buffer(obuf, slen);
255 209
256 return write(tdt->toc_fd, obuf, slen); 210 return write(tdt->toc_fd, obuf, slen);
257 } 211 }
258 212
259 213 static int wait_reply(struct gaim_connection *gc, char *buffer, size_t buflen) {
260 static int wait_reply(struct gaim_connection *gc, char *buffer, size_t buflen)
261 {
262 size_t res=-1;
263 int read_rv = -1;
264 struct sflap_hdr *hdr=(struct sflap_hdr *)buffer;
265 struct toc_data *tdt = (struct toc_data *)gc->proto_data; 214 struct toc_data *tdt = (struct toc_data *)gc->proto_data;
266 char *c; 215 struct sflap_hdr *hdr;
267 216 int ret;
268 if(buflen < sizeof(struct sflap_hdr)) { 217
269 do_error_dialog(_("Unable to read from server: Buffer too small"), 218 if (read(tdt->toc_fd, buffer, sizeof(struct sflap_hdr)) < 0) {
270 _("Gaim - Error (internal)")); 219 debug_printf("error, couldn't read flap header\n");
271 return -1; 220 return -1;
272 } 221 }
273 222
274 while((read_rv = read(tdt->toc_fd, buffer, 1))) { 223 hdr = (struct sflap_hdr *)buffer;
275 if (read_rv < 0 || read_rv > 1) 224
276 return -1; 225 if (buflen < ntohs(hdr->len)) {
277 if (buffer[0] == '*') 226 /* fake like there's a read error */
278 break; 227 debug_printf("buffer too small (have %d, need %d)\n", buflen, ntohs(hdr->len));
279 228 return -1;
280 } 229 }
281 230
282 read_rv = read(tdt->toc_fd, buffer+1, sizeof(struct sflap_hdr) - 1); 231 if (ntohs(hdr->len) > 0) {
283 232 ret = read(tdt->toc_fd, buffer + sizeof(struct sflap_hdr), ntohs(hdr->len));
284 if (read_rv < 0) 233 buffer[sizeof(struct sflap_hdr) + ret] = '\0';
285 return read_rv; 234 return ret;
286 235 } else return 0;
287 res = read_rv + 1; 236 }
288 237
289 238 static unsigned char *roast_password(char *pass) {
290 sprintf(debug_buff, "Rcv: %s %s\n",print_header(buffer), ""); 239 /* Trivial "encryption" */
291 debug_print(debug_buff); 240 static char rp[256];
292 241 static char *roast = ROAST;
293 242 int pos=2;
294 if(buflen < sizeof(struct sflap_hdr) + ntohs(hdr->len) + 1) { 243 int x;
295 do_error_dialog(_("Unable to read from server: Too much information"), 244 strcpy(rp, "0x");
296 _("Gaim - Error (internal)")); 245 for (x=0;(x<150) && pass[x]; x++)
297 return -1; 246 pos+=sprintf(&rp[pos],"%02x", pass[x] ^ roast[x % strlen(roast)]);
298 } 247 rp[pos]='\0';
299 248 return rp;
300 while (res < (sizeof(struct sflap_hdr) + ntohs(hdr->len))) { 249 }
301 read_rv = read(tdt->toc_fd, buffer + res, (ntohs(hdr->len) + sizeof(struct sflap_hdr)) - res); 250
302 if(read_rv < 0) return read_rv; 251 static void toc_callback(gpointer data, gint source, GdkInputCondition condition) {
303 res += read_rv; 252 struct gaim_connection *gc = (struct gaim_connection *)data;
304 /* my feeling is this will kill us. if there's data pending then we'll come right back 253 struct toc_data *tdt = (struct toc_data *)gc->proto_data;
305 * to where we are now. possible workarounds are to remove the input watcher until 254 struct sflap_hdr *hdr;
306 * we're done with this part 255 struct signon so;
307 while(gtk_events_pending()) 256 char buf[8 * 1024], *c;
308 gtk_main_iteration(); 257 char snd[MSG_LEN];
309 */ 258
310 } 259 if (condition & GDK_INPUT_EXCEPTION) {
311 260 debug_printf("gdk_input exception! check internet connection\n");
312 if (res >= sizeof(struct sflap_hdr)) 261 hide_login_progress(gc, _("Connection Closed"));
313 buffer[res]='\0'; 262 signoff(gc);
314 else 263 return;
315 return res - sizeof(struct sflap_hdr); 264 }
316 265
317 switch(hdr->type) { 266 /* there's data waiting to be read, so read it. */
318 case TYPE_SIGNON: 267 if (wait_reply(gc, buf, 8 * 1024) < 0) {
319 memcpy(&peer_ver, buffer + sizeof(struct sflap_hdr), 4); 268 hide_login_progress(gc, _("Connection Closed"));
320 peer_ver = ntohl(peer_ver); 269 signoff(gc);
270 return;
271 }
272
273 if (tdt->state == STATE_FLAPON) {
274 hdr = (struct sflap_hdr *)buf;
275 if (hdr->type != TYPE_SIGNON)
276 debug_printf("problem, hdr->type != TYPE_SIGNON\n");
277 else
278 debug_printf("* TOC sends Client FLAP SIGNON\n");
321 tdt->seqno = ntohs(hdr->seqno); 279 tdt->seqno = ntohs(hdr->seqno);
322 tdt->state = STATE_SIGNON_REQUEST; 280 tdt->state = STATE_SIGNON_REQUEST;
323 break; 281
324 case TYPE_DATA: 282 debug_printf("* Client sends TOC FLAP SIGNON\n");
325 if (!strncasecmp(buffer + sizeof(struct sflap_hdr), "SIGN_ON:", strlen("SIGN_ON:"))) 283 g_snprintf(so.username, sizeof(so.username), "%s", gc->username);
326 tdt->state = STATE_SIGNON_ACK; 284 so.ver = htonl(1);
327 else if (!strncasecmp(buffer + sizeof(struct sflap_hdr), "CONFIG:", strlen("CONFIG:"))) { 285 so.tag = htons(1);
328 tdt->state = STATE_CONFIG; 286 so.namelen = htons(strlen(so.username));
329 } else if (!strncasecmp(buffer + sizeof(struct sflap_hdr), "ERROR:", strlen("ERROR:"))) { 287 if (sflap_send(gc, (char *)&so, ntohs(so.namelen) + 8, TYPE_SIGNON) < 0) {
330 c = strtok(buffer + sizeof(struct sflap_hdr) + strlen("ERROR:"), ":"); 288 hide_login_progress(gc, _("Disconnected."));
331 show_error_dialog(c); 289 signoff(gc);
290 return;
332 } 291 }
333 292
334 sprintf(debug_buff, "Data: %s\n",buffer + sizeof(struct sflap_hdr)); 293 debug_printf("* Client sends TOC \"toc_signon\" message\n");
335 debug_print(debug_buff); 294 g_snprintf(snd, sizeof snd, "toc_signon %s %d %s %s %s \"%s\"",
336 295 AUTH_HOST, AUTH_PORT, normalize(gc->username),
337 break; 296 roast_password(gc->password), LANGUAGE, REVISION);
338 default: 297 if (sflap_send(gc, snd, -1, TYPE_DATA) < 0) {
339 sprintf(debug_buff, "Unknown/unimplemented packet type %d\n",hdr->type); 298 hide_login_progress(gc, _("Disconnected."));
340 debug_print(debug_buff); 299 signoff(gc);
341 } 300 return;
342 return res; 301 }
343 } 302
344 303 set_login_progress(gc, 3, _("Waiting for reply..."));
345
346
347 void toc_callback( gpointer data,
348 gint source,
349 GdkInputCondition condition )
350 {
351 char *buf;
352 char *c;
353 char *l;
354 struct gaim_connection *gc = (struct gaim_connection *)data;
355
356 buf = g_malloc(2 * BUF_LONG);
357 if (wait_reply(gc, buf, 2 * BUF_LONG) < 0) {
358 hide_login_progress(gc, "Connection Closed");
359 signoff(gc); /* this will free gc for us */
360 g_free(buf);
361 return; 304 return;
362 } 305 }
363 306
364 307 if (tdt->state == STATE_SIGNON_REQUEST) {
365 c=strtok(buf+sizeof(struct sflap_hdr),":"); /* Ditch the first part */ 308 debug_printf("* TOC sends client SIGN_ON reply\n");
366 if (!strcasecmp(c,"UPDATE_BUDDY")) { 309 if (strncasecmp(buf + sizeof(struct sflap_hdr), "SIGN_ON", strlen("SIGN_ON"))) {
367 char *uc; 310 debug_printf("Didn't get SIGN_ON! buf was: %s\n", buf+sizeof(struct sflap_hdr));
311 hide_login_progress(gc, _("Authentication Failed"));
312 signoff(gc);
313 return;
314 }
315 /* we're supposed to check that it's really TOC v1 here but we know it is ;) */
316 debug_printf("TOC version: %s\n", buf + sizeof(struct sflap_hdr) + 4);
317
318 /* we used to check for the CONFIG here, but we'll wait until we've sent our
319 * version of the config and then the toc_init_done message. we'll come back to
320 * the callback in a better state if we get CONFIG anyway */
321
322 gc->options = gc->user->options;
323 tdt->state = STATE_ONLINE;
324
325 account_online(gc);
326 serv_finish_login(gc);
327
328 do_import(0, gc);
329
330 /* Client sends TOC toc_init_done message */
331 debug_printf("* Client sends TOC toc_init_done message\n");
332 g_snprintf(snd, sizeof snd, "toc_init_done");
333 sflap_send(gc, snd, -1, TYPE_DATA);
334
335 g_snprintf(snd, sizeof snd, "toc_set_caps %s %s %s %s %s",
336 FILE_SEND_UID, FILE_GET_UID, B_ICON_UID, IMAGE_UID, VOICE_UID);
337 sflap_send(gc, snd, -1, TYPE_DATA);
338
339 if (gc->keepalive < 0)
340 update_keepalive(gc, gc->options & OPT_USR_KEEPALV);
341
342 return;
343 }
344
345 debug_printf("From TOC server: %s\n", buf + sizeof(struct sflap_hdr));
346
347 c = strtok(buf + sizeof(struct sflap_hdr), ":"); /* Ditch the first part */
348
349 if (!strcasecmp(c, "SIGN_ON")) {
350 /* we should only get here after a PAUSE */
351 if (tdt->state != STATE_PAUSE)
352 debug_printf("got SIGN_ON but not PAUSE!\n");
353 else {
354 tdt->state = STATE_ONLINE;
355 do_error_dialog(_("TOC has come back from its pause. You may now send"
356 " messages again."), _("TOC Resume"));
357 do_import(0, gc);
358 g_snprintf(snd, sizeof snd, "toc_init_done");
359 sflap_send(gc, snd, -1, TYPE_DATA);
360 }
361 } else if (!strcasecmp(c, "CONFIG")) {
362 c = strtok(NULL, ":");
363 parse_toc_buddy_list(gc, c, 0);
364 } else if (!strcasecmp(c, "NICK")) {
365 c = strtok(NULL, ":");
366 g_snprintf(gc->username, sizeof(gc->username), "%s", c);
367 } else if (!strcasecmp(c, "IM_IN")) {
368 char *away, *message;
369 int a = 0;
370
371 c = strtok(NULL, ":");
372 away = strtok(NULL, ":");
373 message = strtok(NULL, ":");
374 a = (away && (*away == 'T')) ? 1 : 0;
375
376 serv_got_im(gc, c, message, a);
377 } else if (!strcasecmp(c, "UPDATE_BUDDY")) {
378 char *l, *uc;
368 int logged, evil, idle, type = 0; 379 int logged, evil, idle, type = 0;
369 time_t signon; 380 time_t signon, time_idle;
370 time_t time_idle; 381
371 382 c = strtok(NULL, ":"); /* name */
372 c = strtok(NULL,":"); /* c is name */ 383 l = strtok(NULL, ":"); /* online */
373
374 l = strtok(NULL,":"); /* l is T/F logged status */
375
376 sscanf(strtok(NULL, ":"), "%d", &evil); 384 sscanf(strtok(NULL, ":"), "%d", &evil);
377 385 sscanf(strtok(NULL, ":"), "%d", &signon);
378 sscanf(strtok(NULL, ":"), "%ld", &signon);
379
380 sscanf(strtok(NULL, ":"), "%d", &idle); 386 sscanf(strtok(NULL, ":"), "%d", &idle);
381 387 uc = strtok(NULL, ":");
382 uc = strtok(NULL, ":"); 388
383 389 logged = (l && (*l == 'T')) ? 1 : 0;
384 390
385 if (!strncasecmp(l,"T",1)) 391 if (uc[0] == 'A') type |= UC_AOL;
386 logged = 1; 392 switch (uc[1]) {
387 else
388 logged = 0;
389
390
391 if (uc[0] == 'A')
392 type |= UC_AOL;
393
394 switch(uc[1]) {
395 case 'A': 393 case 'A':
396 type |= UC_ADMIN; 394 type |= UC_ADMIN;
397 break; 395 break;
398 case 'U': 396 case 'U':
399 type |= UC_UNCONFIRMED; 397 type |= UC_UNCONFIRMED;
402 type |= UC_NORMAL; 400 type |= UC_NORMAL;
403 break; 401 break;
404 default: 402 default:
405 break; 403 break;
406 } 404 }
407 405 if (uc[0] == 'U') type |= UC_UNAVAILABLE;
408 switch(uc[2]) { 406
409 case 'U': 407 if (idle) { time(&time_idle); time_idle -= idle * 60; }
410 type |= UC_UNAVAILABLE; 408 else time_idle = 0;
411 break; 409
412 default: 410 serv_got_update(gc, c, logged, evil, signon, time_idle, type, 0);
413 break;
414 }
415
416 if (idle) {
417 time(&time_idle);
418 time_idle -= idle*60;
419 } else
420 time_idle = 0;
421
422 serv_got_update(gc, c, logged, evil, signon, time_idle, type, 0);
423
424 } else if (!strcasecmp(c, "CONFIG")) {
425 /* do we want to load the buddy list again here? */
426 c = strtok(NULL,":");
427 parse_toc_buddy_list(gc, c, 0);
428 } else if (!strcasecmp(c, "ERROR")) { 411 } else if (!strcasecmp(c, "ERROR")) {
429 /* This should be handled by wait_reply 412 c = strtok(NULL, ":");
430 c = strtok(NULL,":");
431 show_error_dialog(c); 413 show_error_dialog(c);
432 */ 414 } else if (!strcasecmp(c, "EVILED")) {
433 } else if (!strcasecmp(c, "NICK")) { 415 int lev;
434 c = strtok(NULL,":");
435 g_snprintf(gc->username, sizeof(gc->username), "%s", c);
436 } else if (!strcasecmp(c, "IM_IN")) {
437 char *away, *message;
438 int a = 0;
439
440 c = strtok(NULL,":");
441 away = strtok(NULL,":");
442
443 message = away;
444
445 while(*message && (*message != ':'))
446 message++;
447
448 message++;
449
450 if (!strncasecmp(away, "T", 1))
451 a = 1;
452 serv_got_im(gc, c, message, a);
453
454 } else if (!strcasecmp(c, "GOTO_URL")) {
455 char *name; 416 char *name;
456 char *url; 417
457 418 sscanf(strtok(NULL, ":"), "%d", &lev);
458 char tmp[256];
459
460 name = strtok(NULL, ":"); 419 name = strtok(NULL, ":");
461 url = strtok(NULL, ":");
462
463
464 g_snprintf(tmp, sizeof(tmp), "http://%s:%d/%s", TOC_HOST, TOC_PORT, url);
465 g_show_info(gc->user, tmp);
466 } else if (!strcasecmp(c, "EVILED")) {
467 int lev;
468 char *name = NULL;
469
470 sscanf(strtok(NULL, ":"), "%d", &lev);
471 name = strtok(NULL, ":");
472
473 sprintf(debug_buff,"%s | %d\n", name, lev);
474 debug_print(debug_buff);
475 420
476 serv_got_eviled(gc, name, lev); 421 serv_got_eviled(gc, name, lev);
477 422 } else if (!strcasecmp(c, "CHAT_JOIN")) {
478 } else if (!strcasecmp(c, "CHAT_JOIN")) { 423 char *name;
479 char *name; 424 int id;
480 int id;
481
482 425
483 sscanf(strtok(NULL, ":"), "%d", &id); 426 sscanf(strtok(NULL, ":"), "%d", &id);
484 name = strtok(NULL, ":"); 427 name = strtok(NULL, ":");
485 serv_got_joined_chat(gc, id, name); 428
486 429 serv_got_joined_chat(gc, id, name);
487 } else if (!strcasecmp(c, "DIR_STATUS")) { 430 } else if (!strcasecmp(c, "CHAT_IN")) {
488 } else if (!strcasecmp(c, "ADMIN_PASSWD_STATUS")) { 431 int id, w;
489 do_error_dialog("Password Change Successeful", "Gaim - Password Change"); 432 char *m, *who, *whisper;
433
434 sscanf(strtok(NULL, ":"), "%d", &id);
435 who = strtok(NULL, ":");
436 whisper = strtok(NULL, ":");
437 m = strtok(NULL, ":");
438
439 w = (whisper && (*whisper == 'T')) ? 1 : 0;
440
441 serv_got_chat_in(gc, id, who, w, m);
490 } else if (!strcasecmp(c, "CHAT_UPDATE_BUDDY")) { 442 } else if (!strcasecmp(c, "CHAT_UPDATE_BUDDY")) {
491 int id; 443 int id;
492 char *in; 444 char *in, *buddy;
493 char *buddy; 445 GSList *bcs = gc->buddy_chats;
494 GSList *bcs = gc->buddy_chats;
495 struct conversation *b = NULL; 446 struct conversation *b = NULL;
496 447
497 sscanf(strtok(NULL, ":"), "%d", &id); 448 sscanf(strtok(NULL, ":"), "%d", &id);
498
499 in = strtok(NULL, ":"); 449 in = strtok(NULL, ":");
500 450
501 while(bcs) { 451 while(bcs) {
502 b = (struct conversation *)bcs->data; 452 b = (struct conversation *)bcs->data;
503 if (id == b->id) 453 if (id == b->id)
504 break; 454 break;
505 bcs = bcs->next; 455 bcs = bcs->next;
506 b = NULL; 456 b = NULL;
507 } 457 }
508 458
509 if (!b) { 459 if (!b) return;
510 g_free(buf); 460
511 return; 461 if (in && (*in == 'T'))
512 } 462 while ((buddy = strtok(NULL, ":")) != NULL)
513
514
515 if (!strcasecmp(in, "T")) {
516 while((buddy = strtok(NULL, ":")) != NULL) {
517 add_chat_buddy(b, buddy); 463 add_chat_buddy(b, buddy);
518 } 464 else
519 } else { 465 while ((buddy = strtok(NULL, ":")) != NULL)
520 while((buddy = strtok(NULL, ":")) != NULL) {
521 remove_chat_buddy(b, buddy); 466 remove_chat_buddy(b, buddy);
522 } 467 } else if (!strcasecmp(c, "CHAT_INVITE")) {
523 } 468 char *name, *who, *message;
524
525 } else if (!strcasecmp(c, "CHAT_LEFT")) {
526 int id; 469 int id;
527 470
528
529 sscanf(strtok(NULL, ":"), "%d", &id);
530
531 serv_got_chat_left(gc, id);
532
533
534 } else if (!strcasecmp(c, "CHAT_IN")) {
535
536 int id, w;
537 char *m;
538 char *who, *whisper;
539
540
541 sscanf(strtok(NULL, ":"), "%d", &id);
542 who = strtok(NULL, ":");
543 whisper = strtok(NULL, ":");
544 m = whisper;
545 while(*m && (*m != ':')) m++;
546 m++;
547
548 if (!strcasecmp(whisper, "T"))
549 w = 1;
550 else
551 w = 0;
552
553 serv_got_chat_in(gc, id, who, w, m);
554
555
556 } else if (!strcasecmp(c, "CHAT_INVITE")) {
557 char *name;
558 char *who;
559 char *message;
560 int id;
561
562
563 name = strtok(NULL, ":"); 471 name = strtok(NULL, ":");
564 sscanf(strtok(NULL, ":"), "%d", &id); 472 sscanf(strtok(NULL, ":"), "%d", &id);
565 who = strtok(NULL, ":"); 473 who = strtok(NULL, ":");
566 message = strtok(NULL, ":"); 474 message = strtok(NULL, ":");
567 475
568 serv_got_chat_invite(gc, name, id, who, message); 476 serv_got_chat_invite(gc, name, id, who, message);
569 477 } else if (!strcasecmp(c, "CHAT_LEFT")) {
570 478 int id;
571 } else if (!strcasecmp(c, "RVOUS_PROPOSE")) { 479
572 char *user; 480 sscanf(strtok(NULL, ":"), "%d", &id);
573 char *uuid; 481
574 char *cookie; 482 serv_got_chat_left(gc, id);
575 int seq; 483 } else if (!strcasecmp(c, "GOTO_URL")) {
576 char *rip, *pip, *vip; 484 char *name, *url, tmp[256];
577 int port; 485
578 int unk[4]; 486 name = strtok(NULL, ":");
579 char *messages[4]; 487 url = strtok(NULL, ":");
580 int subtype, files, totalsize; 488
581 char *name; 489 g_snprintf(tmp, sizeof(tmp), "http://%s:%d/%s", TOC_HOST, TOC_PORT, url);
582 char *tmp; 490 g_show_info(gc->user, tmp);
583 int i; 491 } else if (!strcasecmp(c, "DIR_STATUS")) {
584 struct file_transfer *ft; 492 } else if (!strcasecmp(c, "ADMIN_NICK_STATUS")) {
585 493 } else if (!strcasecmp(c, "ADMIN_PASSWD_STATUS")) {
586 494 do_error_dialog(_("Password Change Successeful"), _("Gaim - Password Change"));
587 user = strtok(NULL, ":"); 495 } else if (!strcasecmp(c, "PAUSE")) {
588 uuid = strtok(NULL, ":"); 496 tdt->state = STATE_PAUSE;
589 cookie = strtok(NULL, ":"); 497 do_error_dialog(_("TOC has sent a PAUSE command. When this happens, TOC ignores"
590 sscanf(strtok(NULL, ":"), "%d", &seq); 498 " any messages sent to it, and may kick you off if you send a"
591 rip = strtok(NULL, ":"); 499 " message. Gaim will prevent anything from going through. This"
592 pip = strtok(NULL, ":"); 500 " is only temporary, please be patient."), _("TOC Pause"));
593 vip = strtok(NULL, ":"); 501 } else if (!strcasecmp(c, "RVOUS_PROPOSE")) {
594 sscanf(strtok(NULL, ":"), "%d", &port); 502 char *user, *uuid, *cookie;
503 int seq;
504 char *rip, *pip, *vip;
505 int port;
506
507 user = strtok(NULL, ":");
508 uuid = strtok(NULL, ":");
509 cookie = strtok(NULL, ":");
510 sscanf(strtok(NULL, ":"), "%d", &seq);
511 rip = strtok(NULL, ":");
512 pip = strtok(NULL, ":");
513 vip = strtok(NULL, ":");
514 sscanf(strtok(NULL, ":"), "%d", &port);
595 515
596 if (!strcmp(uuid, FILE_SEND_UID)) { 516 if (!strcmp(uuid, FILE_SEND_UID)) {
597 /* we're getting a file */ 517 /* they want us to get a file */
598 for (i=0; i<4; i++) { 518 int unk[4], i;
599 sscanf(strtok(NULL, ":"), "%d", &unk[i]); 519 char *messages[4], *tmp, *name;
600 if (unk[i] == 10001) 520 int subtype, files, totalsize = 0;
601 break; 521 struct file_transfer *ft;
602 messages[i] = frombase64(strtok(NULL, ":")); 522
603 } 523 for (i = 0; i < 4; i++) {
604 tmp = frombase64(strtok(NULL, ":")); 524 sscanf(strtok(NULL, ":"), "%d", unk + i);
605 subtype = tmp[1]; 525 if (unk[1] == 10001) break;
606 files = tmp[3]; /* These are fine */ 526 messages[i] = frombase64(strtok(NULL, ":"));
607 527 }
608 totalsize = 0; 528 tmp = frombase64(strtok(NULL, ":"));
529
530 subtype = tmp[1];
531 files = tmp[3];
532
609 totalsize |= (tmp[4] << 24) & 0xff000000; 533 totalsize |= (tmp[4] << 24) & 0xff000000;
610 totalsize |= (tmp[5] << 16) & 0x00ff0000; 534 totalsize |= (tmp[5] << 16) & 0x00ff0000;
611 totalsize |= (tmp[6] << 8) & 0x0000ff00; 535 totalsize |= (tmp[6] << 8) & 0x0000ff00;
612 totalsize |= (tmp[7] << 0) & 0x000000ff; 536 totalsize |= (tmp[7] << 0) & 0x000000ff;
613 537
614 name = tmp + 8; 538 if (!totalsize) {
615 539 g_free(tmp);
616 ft = g_new0(struct file_transfer, 1); 540 for (i--; i >= 0; i--) g_free(messages[i]);
617 541 return;
618 ft->cookie = g_strdup(cookie); 542 }
619 ft->ip = g_strdup(pip); 543
620 ft->port = port; 544 name = tmp + 8;
621 if (i) 545
622 ft->message = g_strdup(messages[0]);
623 else
624 ft->message = NULL;
625 ft->filename = g_strdup(name);
626 ft->user = g_strdup(user);
627 ft->size = totalsize;
628 sprintf(ft->UID, "%s", FILE_SEND_UID);
629 ft->gc = gc;
630
631 g_free(tmp);
632
633 for (i--; i >= 0; i--)
634 g_free(messages[i]);
635
636 if (totalsize) /* sanity check */
637 accept_file_dialog(ft);
638 } else if (!strcmp(uuid, FILE_GET_UID)) {
639 /* we're sending a file */
640 for (i=0; i<4; i++) {
641 sscanf(strtok(NULL, ":"), "%d", &unk[i]);
642 if (unk[i] == 10001)
643 break;
644 messages[i] = frombase64(strtok(NULL, ":"));
645 }
646 tmp = frombase64(strtok(NULL, ":"));
647 ft = g_new0(struct file_transfer, 1); 546 ft = g_new0(struct file_transfer, 1);
648
649 ft->cookie = g_strdup(cookie); 547 ft->cookie = g_strdup(cookie);
650 ft->ip = g_strdup(pip); 548 ft->ip = g_strdup(pip);
651 ft->port = port; 549 ft->port = port;
652 if (i) 550 if (i) ft->message = g_strdup(messages[0]);
653 ft->message = g_strdup(messages[0]); 551 else ft->message = NULL;
654 else 552 ft->filename = g_strdup(name);
655 ft->message = NULL;
656 ft->user = g_strdup(user); 553 ft->user = g_strdup(user);
657 sprintf(ft->UID, "%s", FILE_GET_UID); 554 ft->size = totalsize;
555 g_snprintf(ft->UID, sizeof(ft->UID), "%s", FILE_SEND_UID);
658 ft->gc = gc; 556 ft->gc = gc;
659 557
660 g_free(tmp); 558 g_free(tmp);
661 559 for (i--; i >= 0; i--) g_free(messages[i]);
662 for (i--; i >= 0; i--) 560
663 g_free(messages[i]); 561 accept_file_dialog(ft);
562 } else if (!strcmp(uuid, FILE_GET_UID)) {
563 /* they want us to send a file */
564 int unk[4], i;
565 char *messages[4], *tmp;
566 struct file_transfer *ft;
567
568 for (i = 0; i < 4; i++) {
569 sscanf(strtok(NULL, ":"), "%d", unk + i);
570 if (unk[i] == 10001) break;
571 messages[i] = frombase64(strtok(NULL, ":"));
572 }
573 tmp = frombase64(strtok(NULL, ":"));
574
575 ft = g_new0(struct file_transfer, 1);
576 ft->cookie = g_strdup(cookie);
577 ft->ip = g_strdup(pip);
578 ft->port = port;
579 if (i) ft->message = g_strdup(messages[0]);
580 else ft->message = NULL;
581 ft->user = g_strdup(user);
582 g_snprintf(ft->UID, sizeof(ft->UID), "%s", FILE_GET_UID);
583 ft->gc = gc;
584
585 g_free(tmp);
586 for (i--; i >= 0; i--) g_free(messages[i]);
664 587
665 accept_file_dialog(ft); 588 accept_file_dialog(ft);
666 } else if (!strcmp(uuid, VOICE_UID)) { 589 } else if (!strcmp(uuid, VOICE_UID)) {
667 /* oh goody. voice over ip. fun stuff. */ 590 /* oh goody. voice over ip. fun stuff. */
668
669 /*
670 } else if (!strcmp(uuid, B_ICON_UID)) { 591 } else if (!strcmp(uuid, B_ICON_UID)) {
592 /* buddy icon... */
671 } else if (!strcmp(uuid, IMAGE_UID)) { 593 } else if (!strcmp(uuid, IMAGE_UID)) {
672 */ 594 /* aka Direct IM */
673
674 } else { 595 } else {
675 sprintf(debug_buff,"don't know what to do with %s\n", 596 debug_printf("Don't know what to do with RVOUS UUID %s\n", uuid);
676 uuid); 597 /* do we have to do anything here? i think it just times out */
677 debug_print(debug_buff);
678 tmp = g_malloc(BUF_LEN);
679 name = frombase64(cookie);
680 snprintf(tmp, BUF_LEN, "toc_rvous_cancel %s %s %s",
681 user, name, uuid);
682 sflap_send(gc, tmp, strlen(tmp), TYPE_DATA);
683 free(name);
684 free(tmp);
685 } 598 }
686 } else { 599 } else {
687 sprintf(debug_buff,"don't know what to do with %s\n", c); 600 debug_printf("don't know what to do with %s\n", c);
688 debug_print(debug_buff); 601 }
689 }
690 g_free(buf);
691 }
692
693
694 int toc_signon(struct gaim_connection *gc)
695 {
696 char buf[BUF_LONG];
697 int res;
698 struct signon so;
699 struct toc_data *tdt = (struct toc_data *)gc->proto_data;
700
701 sprintf(debug_buff,"State = %d\n", tdt->state);
702 debug_print(debug_buff);
703
704 if ((res = write(tdt->toc_fd, FLAPON, strlen(FLAPON))) < 0)
705 return res;
706 /* Wait for signon packet */
707
708 tdt->state = STATE_FLAPON;
709
710 if ((res = wait_reply(gc, buf, sizeof(buf)) < 0))
711 return res;
712
713 if (tdt->state != STATE_SIGNON_REQUEST) {
714 sprintf(debug_buff, "State should be %d, but is %d instead\n", STATE_SIGNON_REQUEST, tdt->state);
715 debug_print(debug_buff);
716 return -1;
717 }
718
719 /* Compose a response */
720
721 g_snprintf(so.username, sizeof(so.username), "%s", gc->username);
722 so.ver = ntohl(1);
723 so.tag = ntohs(1);
724 so.namelen = htons(strlen(so.username));
725
726 sflap_send(gc, (char *)&so, ntohs(so.namelen) + 8, TYPE_SIGNON);
727
728 g_snprintf(buf, sizeof(buf),
729 "toc_signon %s %d %s %s %s \"%s\"",
730 AUTH_HOST, AUTH_PORT, normalize(gc->username), roast_password(gc->password),
731 LANGUAGE, REVISION);
732
733 sprintf(debug_buff,"Send: %s\n", buf);
734 debug_print(debug_buff);
735
736 return sflap_send(gc, buf, -1, TYPE_DATA);
737 }
738
739 int toc_wait_signon(struct gaim_connection *gc)
740 {
741 /* Wait for the SIGNON to be approved */
742 struct toc_data *tdt = (struct toc_data *)gc->proto_data;
743 char buf[BUF_LONG];
744 int res;
745 res = wait_reply(gc, buf, sizeof(buf));
746 if (res < 0)
747 return res;
748 if (tdt->state != STATE_SIGNON_ACK) {
749 sprintf(debug_buff, "State should be %d, but is %d instead\n",STATE_SIGNON_ACK, tdt->state);
750 debug_print(debug_buff);
751 return -1;
752 }
753 return 0;
754 }
755
756 #ifdef _WIN32
757 gint win32_read()
758 {
759 int ret;
760 struct fd_set fds;
761 struct timeval tv;
762
763 FD_ZERO(&fds);
764
765 tv.tv_sec = 0;
766 tv.tv_usec = 200;
767
768 FD_SET(toc_fd, &fds);
769
770 ret = select(toc_fd + 1, &fds, NULL, NULL, &tv);
771
772 if (ret == 0) {
773 return TRUE;
774 }
775
776 toc_callback(NULL, 0, (GdkInputCondition)0);
777 return TRUE;
778 }
779 #endif
780
781
782 char *toc_wait_config(struct gaim_connection *gc)
783 {
784 /* Waits for configuration packet, returning the contents of the packet */
785 struct toc_data *tdt = (struct toc_data *)gc->proto_data;
786 static char buf[BUF_LONG];
787 int res;
788 res = wait_reply(gc, buf, sizeof(buf));
789 if (res < 0)
790 return NULL;
791 /* Apparently, the toc_config is optional. *VERY* Optional
792 */
793 if (tdt->state != STATE_CONFIG) {
794 res = 0;
795 } else {
796 res = 1;
797 }
798 /* At this point, it's time to setup automatic handling of incoming packets */
799 tdt->state = STATE_ONLINE;
800 #ifdef _WIN32
801 win32_r = gtk_timeout_add(1000, (GtkFunction)win32_read, NULL);
802 #else
803 gc->inpa = gdk_input_add(tdt->toc_fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, toc_callback, gc);
804 #endif
805 if (res)
806 return buf;
807 else
808 return NULL;
809 } 602 }
810 603
811 void toc_build_config(struct gaim_connection *gc, char *s, int len, gboolean show) 604 void toc_build_config(struct gaim_connection *gc, char *s, int len, gboolean show)
812 { 605 {
813 GSList *grp = gc->groups; 606 GSList *grp = gc->groups;
1020 813
1021 static void toc_add_buddy(struct gaim_connection *g, char *name) { 814 static void toc_add_buddy(struct gaim_connection *g, char *name) {
1022 char buf[1024]; 815 char buf[1024];
1023 g_snprintf(buf, sizeof(buf), "toc_add_buddy %s", normalize(name)); 816 g_snprintf(buf, sizeof(buf), "toc_add_buddy %s", normalize(name));
1024 sflap_send(g, buf, -1, TYPE_DATA); 817 sflap_send(g, buf, -1, TYPE_DATA);
818 toc_set_config(g);
1025 } 819 }
1026 820
1027 static void toc_add_buddies(struct gaim_connection *g, GList *buddies) { 821 static void toc_add_buddies(struct gaim_connection *g, GList *buddies) {
1028 char buf[MSG_LEN]; 822 char buf[MSG_LEN];
1029 int n; 823 int n;
1042 836
1043 static void toc_remove_buddy(struct gaim_connection *g, char *name) { 837 static void toc_remove_buddy(struct gaim_connection *g, char *name) {
1044 char buf[1024]; 838 char buf[1024];
1045 g_snprintf(buf, sizeof(buf), "toc_remove_buddy %s", normalize(name)); 839 g_snprintf(buf, sizeof(buf), "toc_remove_buddy %s", normalize(name));
1046 sflap_send(g, buf, -1, TYPE_DATA); 840 sflap_send(g, buf, -1, TYPE_DATA);
841 toc_set_config(g);
1047 } 842 }
1048 843
1049 static void toc_set_idle(struct gaim_connection *g, int time) { 844 static void toc_set_idle(struct gaim_connection *g, int time) {
1050 char buf[256]; 845 char buf[256];
1051 g_snprintf(buf, sizeof(buf), "toc_set_idle %d", time); 846 g_snprintf(buf, sizeof(buf), "toc_set_idle %d", time);