00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef lint
00021 static const char rcsid[] = "$Id: channel_events.c,v 1.6 2008-10-17 15:57:43 sven Exp $";
00022 #endif
00023
00024 #include "server.h"
00025
00026 static bind_list_t channel_raw_binds[];
00027
00028
00029 static void clear_masklist(channel_mask_list_t *l);
00030 static int got_list_item(void *client_data, char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[]);
00031 static int got_list_end(void *client_data, char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[]);
00032 static void clear_masklists(channel_t *chan);
00033
00034 void channel_events_init()
00035 {
00036 bind_table_t *table;
00037
00038 bind_add_list("raw", channel_raw_binds);
00039 table = bind_table_lookup_or_fake("raw");
00040 if (!table) return;
00041
00042
00043
00044 bind_entry_add(table, NULL, "367", "banlistitem", BIND_WANTS_CD, got_list_item, (void *)'b', NULL);
00045 bind_entry_add(table, NULL, "346", "invitelistitem", BIND_WANTS_CD, got_list_item, (void *)'I', NULL);
00046 bind_entry_add(table, NULL, "348", "exceptlistitem", BIND_WANTS_CD, got_list_item, (void *)'e', NULL);
00047 bind_entry_add(table, NULL, "368", "banlistend", BIND_WANTS_CD, got_list_end, (void *)'b', NULL);
00048 bind_entry_add(table, NULL, "347", "invitelistend", BIND_WANTS_CD, got_list_end, (void *)'I', NULL);
00049 bind_entry_add(table, NULL, "349", "exceptlistend", BIND_WANTS_CD, got_list_end, (void *)'e', NULL);
00050 }
00051
00052 static inline void free_member(channel_member_t *m)
00053 {
00054 if (m->nick) free(m->nick);
00055 if (m->uhost) free(m->uhost);
00056 free(m);
00057 }
00058
00059 static void clear_masklists(channel_t *chan)
00060 {
00061 int i;
00062
00063 for (i = 0; i < chan->nlists; i++) {
00064 clear_masklist(chan->lists[i]);
00065 }
00066 if (chan->lists) free(chan->lists);
00067 chan->nlists = 0;
00068 chan->lists = NULL;
00069 }
00070
00071 static void clear_masklist(channel_mask_list_t *l)
00072 {
00073 channel_mask_t *m, *next;
00074
00075 for (m = l->head; m; m = next) {
00076 next = m->next;
00077 if (m->mask) free(m->mask);
00078 if (m->set_by) free(m->set_by);
00079 free(m);
00080 }
00081 memset(l, 0, sizeof(l));
00082 }
00083
00084
00085 void channel_free_online(channel_t *chan)
00086 {
00087 channel_member_t *m, *next_mem;
00088 int i;
00089
00090 for (m = chan->member_head; m; m = next_mem) {
00091 next_mem = m->next;
00092 uhost_cache_decref(m->nick);
00093 free_member(m);
00094 }
00095
00096 if (chan->topic) free(chan->topic);
00097 if (chan->topic_nick) free(chan->topic_nick);
00098 if (chan->key) free(chan->key);
00099
00100 clear_masklists(chan);
00101
00102 for (i = 0; i < chan->nargs; i++) {
00103 if (chan->args[i].value) free(chan->args[i].value);
00104 }
00105 if (chan->args) free(chan->args);
00106
00107 chan->topic = chan->topic_nick = chan->key = NULL;
00108 chan->args = NULL;
00109 chan->member_head = NULL;
00110 chan->status = chan->nargs = chan->nmembers = 0;
00111 chan->limit = -1;
00112 }
00113
00114 void channel_events_destroy()
00115 {
00116 bind_rem_list("raw", channel_raw_binds);
00117 }
00118
00119 static channel_member_t *channel_add_member(channel_t *chan, const char *nick, const char *uhost)
00120 {
00121 channel_member_t *m;
00122
00123
00124 for (m = chan->member_head; m; m = m->next) {
00125 if (!(current_server.strcmp)(m->nick, nick)) break;
00126 }
00127
00128
00129 if (!m) {
00130 m = calloc(1, sizeof(*m));
00131 m->nick = strdup(nick);
00132 timer_get_now_sec(&m->join_time);
00133 m->next = chan->member_head;
00134 chan->member_head = m;
00135 chan->nmembers++;
00136 }
00137
00138
00139 if (uhost && !m->uhost) {
00140 m->uhost = strdup(uhost);
00141 }
00142
00143 uhost_cache_addref(nick, uhost);
00144
00145 return(m);
00146 }
00147
00148 channel_member_t *channel_lookup_member(channel_t *chan, const char *nick)
00149 {
00150 channel_member_t *m;
00151
00152 for (m = chan->member_head; m; m = m->next) {
00153 if (!(current_server.strcmp)(m->nick, nick)) break;
00154 }
00155 return(m);
00156 }
00157
00158
00159 void channel_on_connect()
00160 {
00161 channel_t *chan;
00162 char *key;
00163 int inactive;
00164
00165 for (chan = channel_head; chan; chan = chan->next) {
00166 channel_get_int(chan, &inactive, "inactive", 0, NULL);
00167 if (inactive) continue;
00168 channel_get(chan, &key, "key", 0, NULL);
00169 if (key && strlen(key)) printserv(SERVER_NORMAL, "JOIN %s %s", chan->name, key);
00170 else printserv(SERVER_NORMAL, "JOIN %s", chan->name);
00171 }
00172 }
00173
00174 void channel_on_join(const char *chan_name, const char *nick, const char *uhost)
00175 {
00176 channel_t *chan;
00177 channel_member_t *m;
00178
00179
00180 chan = channel_probe(chan_name, 1);
00181 if (!chan) return;
00182
00183
00184 m = channel_add_member(chan, nick, uhost);
00185
00186
00187 if (match_my_nick(nick)) {
00188 int i;
00189 chan->bot = m;
00190 chan->status |= (CHANNEL_WHOLIST | CHANNEL_JOINED);
00191 printserv(SERVER_NORMAL, "WHO %s\r\n", chan_name);
00192 printserv(SERVER_NORMAL, "MODE %s\r\n", chan_name);
00193 for (i = 0; i < chan->nlists; i++) {
00194 chan->lists[i]->loading = 1;
00195 }
00196 printserv(SERVER_NORMAL, "MODE %s %s\r\n", chan_name, current_server.type1modes);
00197 }
00198 }
00199
00200 void channel_on_leave(const char *chan_name, const char *nick, const char *uhost, user_t *u)
00201 {
00202 channel_t *chan;
00203 channel_member_t *prev = NULL, *m;
00204
00205 chan = channel_probe(chan_name, 0);
00206 if (!chan) return;
00207
00208 uhost_cache_decref(nick);
00209 for (m = chan->member_head; m; m = m->next) {
00210 if (!(current_server.strcmp)(m->nick, nick)) break;
00211 prev = m;
00212 }
00213 if (!m) return;
00214
00215 if (prev) prev->next = m->next;
00216 else chan->member_head = m->next;
00217 free_member(m);
00218 chan->nmembers--;
00219
00220 bind_check(BT_leave, u ? &u->settings[0].flags : NULL, chan_name, nick, uhost, u, chan_name);
00221
00222
00223 if (match_my_nick(nick)) {
00224 if (chan->flags & CHANNEL_STATIC) channel_free_online(chan);
00225 else channel_free(chan);
00226 }
00227 }
00228
00229 void channel_on_quit(const char *nick, const char *uhost, user_t *u)
00230 {
00231 channel_t *chan;
00232
00233 for (chan = channel_head; chan; chan = chan->next) {
00234 channel_on_leave(chan->name, nick, uhost, u);
00235 }
00236 }
00237
00238 void channel_on_nick(const char *old_nick, const char *new_nick)
00239 {
00240 channel_t *chan;
00241 channel_member_t *m;
00242
00243 uhost_cache_swap(old_nick, new_nick);
00244
00245 for (chan = channel_head; chan; chan = chan->next) {
00246 for (m = chan->member_head; m; m = m->next) {
00247 if (!(current_server.strcmp)(m->nick, old_nick)) {
00248 str_redup(&m->nick, new_nick);
00249 break;
00250 }
00251 }
00252 }
00253 }
00254
00255
00256 static int got352(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
00257 {
00258 char *chan_name, *nick, *uhost, *flags, *ptr, changestr[3];
00259 int i;
00260 channel_member_t *m;
00261 channel_t *chan = NULL;
00262 chan_name = args[1];
00263 chan = channel_probe(chan_name, 0);
00264 if (!chan) return(0);
00265 nick = args[5];
00266 flags = args[6];
00267 uhost = egg_mprintf("%s@%s", args[2], args[3]);
00268 m = channel_add_member(chan, nick, uhost);
00269 changestr[0] = '+';
00270 changestr[2] = 0;
00271 flags++;
00272 while (*flags) {
00273 ptr = strchr(current_server.whoprefix, *flags);
00274 if (ptr) {
00275 i = ptr - current_server.whoprefix;
00276 changestr[1] = current_server.modeprefix[i];
00277 flag_merge_str(&m->mode, changestr);
00278 }
00279 flags++;
00280 }
00281 free(uhost);
00282 return(0);
00283 }
00284
00285
00286 static int got315(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
00287 {
00288 char *chan_name = args[1];
00289 channel_t *chan = NULL;
00290
00291 channel_probe(chan_name, 0);
00292 if (chan) chan->status &= ~CHANNEL_WHOLIST;
00293 return(0);
00294 }
00295
00296
00297 static int got353(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
00298 {
00299 char *chan_name, *nick, *nicks, *flags, *ptr, *prefixptr, changestr[3];
00300 int i;
00301 channel_member_t *m;
00302 channel_t *chan = NULL;
00303
00304 chan_name = args[2];
00305 chan = channel_probe(chan_name, 0);
00306 if (!chan) return(0);
00307
00308 nicks = strdup(args[3]);
00309 ptr = nicks;
00310 changestr[0] = '+';
00311 changestr[2] = 0;
00312 while (ptr && *ptr) {
00313 while (isspace(*ptr)) ptr++;
00314 flags = ptr;
00315 while (strchr(current_server.whoprefix, *ptr)) ptr++;
00316 nick = ptr;
00317 while (*ptr && !isspace(*ptr)) ptr++;
00318 if (*ptr) *ptr = 0;
00319 else ptr = NULL;
00320 m = channel_add_member(chan, nick, NULL);
00321 *nick = 0;
00322 while (*flags) {
00323 prefixptr = strchr(current_server.whoprefix, *flags);
00324 if (prefixptr) {
00325 i = prefixptr - current_server.whoprefix;
00326 changestr[1] = current_server.modeprefix[i];
00327 flag_merge_str(&m->mode, changestr);
00328 }
00329 flags++;
00330 }
00331 if (ptr) ptr++;
00332 }
00333 free(nicks);
00334 return(0);
00335 }
00336
00337
00338 static int got366(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
00339 {
00340 char *chan_name = args[1];
00341 channel_t *chan = NULL;
00342
00343 chan = channel_probe(chan_name, 0);
00344 if (chan) chan->status &= ~CHANNEL_NAMESLIST;
00345 return(0);
00346 }
00347
00348
00349 static int gottopic(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
00350 {
00351 char *chan_name = args[0];
00352 char *topic = args[1];
00353 channel_t *chan = NULL;
00354
00355 chan = channel_probe(chan_name, 0);
00356 if (!chan) return(0);
00357
00358 str_redup(&chan->topic, topic);
00359 if (chan->topic_nick) free(chan->topic_nick);
00360 if (from_uhost) chan->topic_nick = egg_mprintf("%s!%s", from_nick, from_uhost);
00361 else chan->topic_nick = strdup(from_nick);
00362 timer_get_now_sec(&chan->topic_time);
00363
00364 return(0);
00365 }
00366
00367
00368 static int got331(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
00369 {
00370 char *chan_name = args[1];
00371 channel_t *chan = NULL;
00372
00373 chan = channel_probe(chan_name, 0);
00374 if (!chan) return(0);
00375
00376 str_redup(&chan->topic, "");
00377 return(0);
00378 }
00379
00380
00381 static int got332(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
00382 {
00383 char *chan_name = args[1];
00384 char *topic = args[2];
00385 channel_t *chan = NULL;
00386
00387 chan = channel_probe(chan_name, 0);
00388 if (!chan) return(0);
00389
00390 str_redup(&chan->topic, topic);
00391 return(0);
00392 }
00393
00394
00395 static int got333(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
00396 {
00397 char *chan_name = args[1];
00398 char *nick = args[2];
00399 char *time = args[3];
00400 channel_t *chan = NULL;
00401
00402 chan = channel_probe(chan_name, 0);
00403 if (!chan) return(0);
00404
00405 str_redup(&chan->topic_nick, nick);
00406 chan->topic_time = atoi(time);
00407 return(0);
00408 }
00409
00410
00411
00412
00413 static int got_list_item(void *client_data, char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
00414 {
00415 char *chan_name = args[1];
00416 char *ban = args[2];
00417 char type = (char) (int) client_data;
00418 channel_t *chan;
00419 channel_mask_list_t *l;
00420
00421 chan = channel_probe(chan_name, 0);
00422 if (!chan) return(0);
00423 l = channel_get_mask_list(chan, type);
00424 if (!l || !(l->loading)) return(0);
00425 channel_add_mask(chan, type, ban, (nargs > 3) ? args[3] : NULL, (nargs > 4) ? atoi(args[4]) : -1);
00426 return(0);
00427 }
00428
00429
00430
00431
00432 static int got_list_end(void *client_data, char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
00433 {
00434 char *chan_name = args[1];
00435 char type = (char) (int) client_data;
00436 channel_t *chan;
00437 channel_mask_list_t *l;
00438
00439 chan = channel_probe(chan_name, 0);
00440 if (!chan) return(0);
00441 l = channel_get_mask_list(chan, type);
00442 if (l) l->loading = 0;
00443
00444 return(0);
00445 }
00446
00447
00448
00449
00450
00451
00452 static int gotjoin(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
00453 {
00454 char *chan = args[0];
00455
00456 channel_on_join(chan, from_nick, from_uhost);
00457 bind_check(BT_join, u ? &u->settings[0].flags : NULL, chan, from_nick, from_uhost, u, chan);
00458 return(0);
00459 }
00460
00461
00462 static int gotpart(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
00463 {
00464 char *chan = args[0];
00465 char *text = args[1];
00466
00467 channel_on_leave(chan, from_nick, from_uhost, u);
00468 bind_check(BT_part, u ? &u->settings[0].flags : NULL, chan, from_nick, from_uhost, u, chan, text);
00469 return(0);
00470 }
00471
00472
00473 static int gotquit(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
00474 {
00475 char *text = args[0];
00476
00477 channel_on_quit(from_nick, from_uhost, u);
00478 bind_check(BT_quit, u ? &u->settings[0].flags : NULL, from_nick, from_nick, from_uhost, u, text);
00479
00480 return(0);
00481 }
00482
00483
00484 static int gotkick(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
00485 {
00486 char *chan = args[0];
00487 char *victim = args[1];
00488 char *text = args[2];
00489 char *uhost;
00490
00491 if (!text) text = "";
00492 uhost = uhost_cache_lookup(victim);
00493 if (!uhost) uhost = "";
00494
00495 channel_on_leave(chan, victim, uhost, u);
00496 bind_check(BT_kick, u ? &u->settings[0].flags : NULL, from_nick, from_nick, from_uhost, u, chan, victim, text);
00497
00498 return(0);
00499 }
00500
00501
00502 static int gotnick(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
00503 {
00504 char *newnick = args[0];
00505
00506 channel_on_nick(from_nick, newnick);
00507 bind_check(BT_nick, u ? &u->settings[0].flags : NULL, from_nick, from_nick, from_uhost, u, newnick);
00508
00509
00510 if (match_my_nick(from_nick)) str_redup(¤t_server.nick, newnick);
00511
00512 return(0);
00513 }
00514
00515
00516
00517
00518
00519 static void parse_chan_mode(char *from_nick, char *from_uhost, user_t *u, int nargs, char *args[], int trigger_bind)
00520 {
00521 int hasarg, curarg, modify_member, modify_channel, modify_list;
00522 channel_member_t *m;
00523 char changestr[3];
00524 char *dest;
00525 char *change;
00526 channel_t *chan;
00527 const char *arg;
00528
00529 if (nargs < 2) return;
00530
00531 dest = args[0];
00532 change = args[1];
00533
00534 chan = channel_probe(dest, 0);
00535 if (!chan) return;
00536
00537 changestr[0] = '+';
00538 changestr[2] = 0;
00539
00540 curarg = 2;
00541 while (*change) {
00542
00543 if (*change == '+' || *change == '-') {
00544 changestr[0] = *change;
00545 change++;
00546 continue;
00547 }
00548
00549
00550
00551 modify_member = modify_channel = modify_list = 0;
00552 if (strchr(current_server.modeprefix, *change)) {
00553 hasarg = 1;
00554 modify_member = 1;
00555 }
00556 else if (strchr(current_server.type1modes, *change)) {
00557 hasarg = 1;
00558 modify_list = 1;
00559 }
00560 else if (strchr(current_server.type2modes, *change)) {
00561 hasarg = 1;
00562 }
00563 else if (strchr(current_server.type3modes, *change)) {
00564 if (changestr[0] == '+') hasarg = 1;
00565 }
00566 else {
00567 modify_channel = 1;
00568 hasarg = 0;
00569 }
00570
00571 if (hasarg) {
00572 if (curarg >= nargs) arg = "";
00573 else arg = args[curarg++];
00574 }
00575 else arg = NULL;
00576
00577 changestr[1] = *change;
00578
00579 if (modify_member) {
00580
00581 m = channel_lookup_member(chan, arg);
00582 flag_merge_str(&m->mode, changestr);
00583 }
00584 else if (modify_channel) {
00585
00586 flag_merge_str(&chan->mode, changestr);
00587 }
00588 else if (modify_list) {
00589
00590 if (changestr[0] == '+') channel_add_mask(chan, *change, arg, from_nick, timer_get_now_sec(NULL));
00591 else channel_del_mask(chan, *change, arg);
00592 }
00593 else if (changestr[0] == '+') {
00594 channel_mode_arg_t *modearg = channel_get_arg(chan, *change);
00595 if (modearg) str_redup(&modearg->value, arg);
00596
00597
00598 switch (*change) {
00599 case 'k':
00600 str_redup(&chan->key, arg);
00601 break;
00602 case 'l':
00603 chan->limit = atoi(arg);
00604 break;
00605 }
00606 }
00607 else {
00608 channel_mode_arg_t *modearg = channel_get_arg(chan, *change);
00609 if (modearg) str_redup(&modearg->value, NULL);
00610
00611
00612 switch (*change) {
00613 case 'k':
00614 if (chan->key) free(chan->key);
00615 chan->key = NULL;
00616 break;
00617 case 'l':
00618 chan->limit = -1;
00619 break;
00620 }
00621 }
00622
00623
00624 if (trigger_bind) bind_check(BT_mode, u ? &u->settings[0].flags : NULL, changestr, from_nick, from_uhost, u, dest, changestr, arg);
00625 change++;
00626 }
00627 }
00628
00629
00630 static int got324(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
00631 {
00632 parse_chan_mode(from_nick, from_uhost, u, nargs-1, args+1, 0);
00633 return(0);
00634 }
00635
00636
00637 static int gotmode(char *from_nick, char *from_uhost, user_t *u, char *cmd, int nargs, char *args[])
00638 {
00639 char *dest = args[0];
00640 char *change = args[1];
00641 char changestr[3];
00642
00643 changestr[0] = '+';
00644 changestr[2] = 0;
00645
00646
00647 if (!strchr(current_server.chantypes, *dest)) {
00648 while (*change) {
00649
00650 if (*change == '+' || *change == '-') {
00651 changestr[0] = *change;
00652 change++;
00653 continue;
00654 }
00655
00656 changestr[1] = *change;
00657 bind_check(BT_mode, u ? &u->settings[0].flags : NULL, changestr, from_nick, from_uhost, u, dest, changestr, NULL);
00658 change++;
00659 }
00660 return(0);
00661 }
00662
00663 parse_chan_mode(from_nick, from_uhost, u, nargs, args, 1);
00664 return(0);
00665 }
00666
00667 static bind_list_t channel_raw_binds[] = {
00668
00669 {NULL, "352", got352},
00670 {NULL, "315", got315},
00671
00672
00673 {NULL, "353", got353},
00674 {NULL, "366", got366},
00675
00676
00677 {NULL, "TOPIC", gottopic},
00678 {NULL, "331", got331},
00679 {NULL, "332", got332},
00680 {NULL, "333", got333},
00681
00682
00683 {NULL, "JOIN", gotjoin},
00684 {NULL, "PART", gotpart},
00685 {NULL, "QUIT", gotquit},
00686 {NULL, "KICK", gotkick},
00687 {NULL, "NICK", gotnick},
00688
00689
00690 {NULL, "324", got324},
00691 {NULL, "MODE", gotmode},
00692
00693 {NULL, NULL, NULL}
00694 };