/* * parse.c: handles messages from the server. Believe it or not. I * certainly wouldn't if I were you. * * Written By Michael Sandrof * * Copyright(c) 1990 * Modified Colten Edwards 1997 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "irc.h" #include "server.h" #include "names.h" #include "vars.h" #include "ctcp.h" #include "hook.h" #include "commands.h" #include "ignore.h" #include "whois.h" #include "lastlog.h" #include "input.h" #include "notice.h" #include "ircaux.h" #include "funny.h" #include "input.h" #include "ircterm.h" #include "flood.h" #include "window.h" #include "screen.h" #include "output.h" #include "numbers.h" #include "parse.h" #include "notify.h" #include "status.h" #include "list.h" #include "misc.h" #include "whowas.h" #include "timer.h" #include "hash.h" #include "fset.h" #include "tcommand.h" #define space ' ' static void strip_modes(char *, char *, char *); extern char *do_nslookup(char *); extern char *random_str(int, int); char *last_split_server = NULL; int in_server_ping = 0; extern char *mircansi(char *); #ifdef COMPRESS_MODES extern char *compress_modes(int, char *, char *); #endif /* TODO: this needs to be someplace better */ /* in cmd_orignick.c */ void check_orig_nick(char *nick); /* * joined_nick: the nickname of the last person who joined the current * channel */ char *joined_nick = NULL; /* public_nick: nick of the last person to send a message to your channel */ char *public_nick = NULL; /* User and host information from server 2.7 */ char *FromUserHost = empty_str; /* doing a PRIVMSG */ int doing_privmsg = 0; int chan_who = 0; /* returns 1 if the ban is on the channel already, 0 if not */ BanList *ban_is_on_channel(char *ban, struct channel *chan) { register BanList *bans; for (bans = chan->bans; bans; bans = bans->next) { if (match(bans->ban, ban) || match(ban, bans->ban)) return bans; else if (!my_stricmp(bans->ban, ban)) return bans; } return NULL; } void fake(void) { bitchsay("--- Fake Message recieved!!! ---"); return; } char *PasteArgs(char **Args, int StartPoint) { int i; for (; StartPoint; Args++, StartPoint--) if (!*Args) return NULL; for (i = 0; Args[i] && Args[i + 1]; i++) Args[i][strlen(Args[i])] = ' '; Args[1] = NULL; return Args[0]; } /* * BreakArgs: breaks up the line from the server, in to where its from, * setting FromUserHost if it should be, and returns all the arguements * that are there. Re-written by phone, dec 1992. */ int BreakArgs(char *Input, char **Sender, char **OutPut, int ig_sender) { int ArgCount = 0; /* * The RFC describes it fully, but in a short form, a line looks like: * [:sender[!user@host]] COMMAND ARGUMENT [[:]ARGUMENT]{0..14} */ /* * Look to see if the optional :sender is present. */ if (!ig_sender) { if (*Input == ':') { *Sender = ++Input; while (*Input && *Input != space) Input++; if (*Input == space) *Input++ = 0; /* * Look to see if the optional !user@host is present. */ FromUserHost = *Sender; while (*FromUserHost && *FromUserHost != '!') FromUserHost++; if (*FromUserHost == '!') *FromUserHost++ = 0; } /* * No sender present. */ else *Sender = FromUserHost = empty_str; } /* * Now we go through the argument list... */ for (;;) { while (*Input && *Input == space) Input++; if (!*Input) break; if (*Input == ':') { OutPut[ArgCount++] = ++Input; break; } OutPut[ArgCount++] = Input; if (ArgCount >= MAXPARA) break; while (*Input && *Input != space) Input++; if (*Input == space) *Input++ = 0; } OutPut[ArgCount] = NULL; return ArgCount; } /* in response to a TOPIC message from the server */ static void p_topic(char *from, char **ArgList) { struct channel *tmp; if (!ArgList[1]) { fake(); return; } tmp = lookup_channel(ArgList[0], from_server, CHAN_NOUNLINK); malloc_strcpy(&tmp->topic, ArgList[1]); if (check_ignore(from, FromUserHost, tmp->channel, IGNORE_TOPICS | IGNORE_CRAP, NULL) != IGNORED) { message_from(ArgList[0], LOG_CRAP); if (do_hook(TOPIC_LIST, "%s %s %s", from, ArgList[0], ArgList[1])) { if (ArgList[1] && *ArgList[1]) { if (get_format(FORMAT_TOPIC_CHANGE_HEADER_FSET)) put_it("%s", convert_output_format(get_format(FORMAT_TOPIC_CHANGE_HEADER_FSET), "%s %s %s %s", update_clock(GET_TIME), from, ArgList[0], ArgList[1])); put_it("%s", convert_output_format(get_format(FORMAT_TOPIC_CHANGE_FSET), "%s %s %s %s", update_clock(GET_TIME), from, ArgList[0], ArgList[1])); } else put_it("%s", convert_output_format(get_format(FORMAT_TOPIC_UNSET_FSET), "%s %s %s", update_clock(GET_TIME), from, ArgList[0])); } message_from(NULL, LOG_CRAP); } update_all_status(curr_scr_win, NULL, 0); } static void p_wallops(char *from, char **ArgList) { char *line; int from_server = strchr(from, '.') ? 1 : 0; if (!(line = PasteArgs(ArgList, 0))) { fake(); return; } if (from_server || check_flooding(from, WALLOP_FLOOD, line, NULL)) { /* The old server check, don't use the whois stuff for servers */ int level; char *high; switch (check_ignore(from, FromUserHost, NULL, IGNORE_WALLOPS, NULL)) { case (IGNORED): return; case (HIGHLIGHTED): high = highlight_char; break; default: high = empty_str; break; } message_from(from, LOG_WALLOP); level = set_lastlog_msg_level(LOG_WALLOP); if (do_hook(WALLOP_LIST, "%s %c %s", from, from_server ? 'S' : '*', line)) put_it("%s", convert_output_format(get_format(from_server ? FORMAT_WALLOP_FSET : FORMAT_WALL_FSET), "%s %s %s %s", update_clock(GET_TIME), from, from_server ? "!" : "*", line)); if (beep_on_level & LOG_WALLOP) beep_em(1); set_lastlog_msg_level(level); message_from(NULL, LOG_CRAP); } } void whoreply(char *from, char **ArgList) { static char format[40]; static int last_width = -1; int ok = 1, voice = 0, opped = 0; char *channel, *user, *host, *server, *nick, *stat, *name; struct channel *chan = NULL; char buf_data[BIG_BUFFER_SIZE + 1]; if (!ArgList[5]) return; if (last_width != get_int_var(CHANNEL_NAME_WIDTH_VAR)) { if ((last_width = get_int_var(CHANNEL_NAME_WIDTH_VAR)) != 0) snprintf(format, 39, "%%-%u.%us \002%%-9s\002 %%-3s %%s@%%s (%%s)", (unsigned char) last_width, (unsigned char) last_width); else strcpy(format, "%s\t\002%-9s\002 %-3s %s@%s (%s)"); } channel = ArgList[0]; user = ArgList[1]; host = ArgList[2]; server = ArgList[3]; nick = ArgList[4]; stat = ArgList[5]; name = ArgList[6]; PasteArgs(ArgList, 6); message_from(channel, LOG_CRAP); *buf_data = 0; strmopencat(buf_data, BIG_BUFFER_SIZE, user, "@", host, NULL); voice = (strchr(stat, '+') != NULL); opped = (strchr(stat, '@') != NULL); if (*stat == 'S') { /* this only true for the header WHOREPLY */ char buffer[BIG_BUFFER_SIZE + 1]; channel = "Channel"; snprintf(buffer, BIG_BUFFER_SIZE, "%s %s %s %s %s %s %s", channel, nick, stat, user, host, server, name); if (do_hook(WHO_LIST, "%s", buffer)) put_it("%s", convert_output_format(get_format(FORMAT_WHO_FSET), "%s %s %s %s %s %s %s", channel, nick, stat, user, host, server, name)); message_from(NULL, LOG_CRAP); return; } if (who_mask) { if (who_mask & WHO_HERE) ok = ok && (*stat == 'H'); if (who_mask & WHO_AWAY) ok = ok && (*stat == 'G'); if (who_mask & WHO_OPS) ok = ok && (*(stat + 1) == '*'); if (who_mask & WHO_LUSERS) ok = ok && (*(stat + 1) != '*'); if (who_mask & WHO_CHOPS) ok = ok && ((*(stat + 1) == '@') || (*(stat + 2) == '@')); if (who_mask & WHO_NAME) ok = ok && wild_match(who_name, user); if (who_mask & WHO_NICK) ok = ok && wild_match(who_nick, nick); if (who_mask & WHO_HOST) ok = ok && wild_match(who_host, host); if (who_mask & WHO_REAL) ok = ok && wild_match(who_real, name); if (who_mask & WHO_SERVER) ok = ok && wild_match(who_server, server); } if (ok) { char buffer[BIG_BUFFER_SIZE + 1]; snprintf(buffer, BIG_BUFFER_SIZE, "%s %s %s %s %s %s %s", channel, nick, stat, user, host, server, name); chan = add_to_channel(channel, nick, from_server, opped, voice, buf_data, server, stat); if (do_hook(WHO_LIST, "%s", buffer)) { if (!get_int_var(SHOW_WHO_HOPCOUNT_VAR)) next_arg(name, &name); put_it("%s", convert_output_format(get_format(FORMAT_WHO_FSET), "%s %s %s %s %s %s %s", channel, nick, stat, user, host, server, name)); } } /* else if ((who_mask && WHO_KILL) && !ok) { put_it("%s", convert_output_format("$G No such match for /whokill", NULL, NULL)); } */ message_from(NULL, LOG_CRAP); } static void p_privmsg(char *from, char **Args) { int level, list_type, flood_type, log_type, no_flood = 1, do_beep = 1; unsigned char ignore_type; char *ptr = NULL, *to; char *high; struct channel *channel = NULL; struct nick_list *tmpnick = NULL; if (!from) return; PasteArgs(Args, 1); to = Args[0]; ptr = Args[1]; if (!to || !ptr) { fake(); return; } doing_privmsg = 1; if (is_channel(to) && im_on_channel(to)) { message_from(to, LOG_MSG); malloc_strcpy(&public_nick, from); log_type = LOG_PUBLIC; ignore_type = IGNORE_PUBLIC; flood_type = PUBLIC_FLOOD; if (!is_on_channel(to, from_server, from)) list_type = PUBLIC_MSG_LIST; else { if (is_current_channel(to, from_server, 0)) list_type = PUBLIC_LIST; else list_type = PUBLIC_OTHER_LIST; channel = lookup_channel(to, from_server, CHAN_NOUNLINK); if (channel) tmpnick = find_nicklist_in_channellist(from, channel, 0); } } else { message_from(from, LOG_MSG); flood_type = MSG_FLOOD; if (my_stricmp(to, get_server_nickname(from_server))) { log_type = LOG_WALL; ignore_type = IGNORE_WALLS; list_type = MSG_GROUP_LIST; } else { log_type = LOG_MSG; ignore_type = IGNORE_MSGS; list_type = MSG_LIST; } } switch (check_ignore(from, FromUserHost, to, ignore_type, ptr)) { case IGNORED: if ((list_type == MSG_LIST) && get_int_var(SEND_IGNORE_MSG_VAR)) send_to_server(SERVER(from_server), "NOTICE %s :%s is ignoring you", from, get_server_nickname(from_server)); doing_privmsg = 0; return; case HIGHLIGHTED: high = highlight_char; break; case CHANNEL_GREP: high = highlight_char; break; default: high = empty_str; break; } ptr = do_ctcp(from, to, ptr); if (!ptr || !*ptr) { doing_privmsg = 0; return; } level = set_lastlog_msg_level(log_type); if (flood_type == PUBLIC_FLOOD) { int blah = 0; if (is_other_flood(channel, tmpnick, PUBLIC_FLOOD, &blah)) { no_flood = 0; flood_prot(tmpnick->nick, FromUserHost, "PUBLIC", flood_type, get_int_var(PUBFLOOD_TIME_VAR), channel->channel); } } else no_flood = check_flooding(from, flood_type, ptr, NULL); { switch (list_type) { case PUBLIC_MSG_LIST: logmsg(LOG_PUBLIC, from, ptr, 0); if (no_flood && do_hook(list_type, "%s %s %s", from, to, ptr)) put_it("%s", convert_output_format(get_format(FORMAT_PUBLIC_MSG_FSET), "%s %s %s %s %s", update_clock(GET_TIME), from, FromUserHost, to, get_int_var(MIRCS_VAR) ? mircansi(ptr) : ptr)); break; case MSG_GROUP_LIST: logmsg(LOG_PUBLIC, from, ptr, 0); if (no_flood && do_hook(list_type, "%s %s %s", from, to, ptr)) put_it("%s", convert_output_format(get_format(FORMAT_MSG_GROUP_FSET), "%s %s %s %s", update_clock(GET_TIME), from, to, get_int_var(MIRCS_VAR) ? mircansi(ptr) : ptr)); break; case MSG_LIST: { if (!no_flood) break; malloc_strcpy(&recv_nick, from); if (away_set) { do_beep = 0; beep_em(get_int_var(BEEP_WHEN_AWAY_VAR)); set_int_var(MSGCOUNT_VAR, get_int_var(MSGCOUNT_VAR) + 1); } logmsg(LOG_MSG, from, ptr, 0); addtabkey(from, "msg"); if (do_hook(list_type, "%s %s", from, ptr)) put_it("%s", convert_output_format(get_format(FORMAT_MSG_FSET), "%s %s %s %s", update_clock(GET_TIME), from, FromUserHost, get_int_var(MIRCS_VAR) ? mircansi(ptr) : ptr)); if (from_server > -1 && get_server_away(from_server) && get_int_var(SEND_AWAY_MSG_VAR)) { send_to_server(SERVER(from_server), "NOTICE %s :%s", from, stripansicodes(convert_output_format (get_format(FORMAT_SEND_AWAY_FSET), "%l %l %s", time(NULL), server_list[from_server].awaytime, get_int_var(MSGLOG_VAR) ? "On" : "Off"))); } break; } case PUBLIC_LIST:{ logmsg(LOG_PUBLIC, from, ptr, 0); if (no_flood && do_hook(list_type, "%s %s %s", from, to, ptr)) put_it("%s", convert_output_format(get_format(FORMAT_PUBLIC_FSET), "%s %s %s %s", update_clock(GET_TIME), from, to, get_int_var(MIRCS_VAR) ? mircansi(ptr) : ptr)); break; } case PUBLIC_OTHER_LIST:{ logmsg(LOG_PUBLIC, from, ptr, 0); if (no_flood && do_hook(list_type, "%s %s %s", from, to, ptr)) put_it("%s", convert_output_format(get_format(FORMAT_PUBLIC_OTHER_FSET), "%s %s %s %s", update_clock(GET_TIME), from, to, get_int_var(MIRCS_VAR) ? mircansi(ptr) : ptr)); break; } /* case */ } /* switch */ } if (beep_on_level & log_type && do_beep) beep_em(1); set_lastlog_msg_level(level); message_from(NULL, LOG_CRAP); doing_privmsg = 0; } static void p_quit(char *from, char **ArgList) { int one_prints = 0; char *chan = NULL; char *Reason; int netsplit = 0; int ignore; PasteArgs(ArgList, 0); if (ArgList[0]) { Reason = ArgList[0]; netsplit = check_split(from, Reason, chan); } else Reason = "?"; ignore = check_ignore(from, FromUserHost, NULL, (netsplit ? IGNORE_SPLITS : IGNORE_QUITS) | IGNORE_ALL, NULL); for (chan = walk_channels(from, 1, from_server); chan; chan = walk_channels(from, 0, -1)) { if (ignore != IGNORED) { message_from(chan, LOG_CRAP); if (do_hook(CHANNEL_SIGNOFF_LIST, "%s %s %s", chan, from, Reason)) one_prints = 1; message_from(NULL, LOG_CURRENT); } } if (one_prints) { chan = what_channel(from, from_server); ignore = check_ignore(from, FromUserHost, chan, (netsplit ? IGNORE_SPLITS : IGNORE_QUITS) | IGNORE_ALL, NULL); message_from(chan, LOG_CRAP); if ((ignore != IGNORED) && do_hook(SIGNOFF_LIST, "%s %s", from, Reason) && !netsplit) put_it("%s", convert_output_format(get_format(FORMAT_CHANNEL_SIGNOFF_FSET), "%s %s %s %s %s", update_clock(GET_TIME), from, FromUserHost, chan, Reason)); message_from(NULL, LOG_CURRENT); } if (!netsplit) check_orig_nick(from); notify_mark(from, NULL, NULL, 0); remove_from_channel(NULL, from, from_server, netsplit, Reason); message_from(NULL, LOG_CRAP); update_all_status(curr_scr_win, NULL, 0); } static void p_pong(char *from, char **ArgList) { int is_server = 0; int i; if (!ArgList[0]) return; is_server = match("*.*", ArgList[0]); if (in_server_ping && is_server) ; { int old_from_server = from_server; for (i = 0; i < number_of_servers; i++) { if ((!my_stricmp(ArgList[0], get_server_name(i)) || !my_stricmp(ArgList[0], get_server_itsname(i))) && is_server_connected(i)) { int old_lag = server_list[i].lag; from_server = i; server_list[i].lag = time(NULL) - server_list[i].lag_time; in_server_ping--; if (old_lag != server_list[i].lag) status_update(1); from_server = old_from_server; return; } } from_server = old_from_server; } if (check_ignore(from, FromUserHost, NULL, IGNORE_PONGS | IGNORE_CRAP, NULL) != IGNORED) { if (!is_server) return; if (!ArgList[1]) say("%s: PONG received from %s", ArgList[0], from); else say("%s: PING received from %s %s", ArgList[0], from, ArgList[1]); } } static void p_error(char *from, char **ArgList) { PasteArgs(ArgList, 0); if (!ArgList[0]) { fake(); return; } say("%s", ArgList[0]); } static void p_channel(char *from, char **ArgList) { char *channel; char *user, *host; struct channel *chan = NULL; struct whowas_list *whowas = NULL; int its_me = 0; if (!strcmp(ArgList[0], "0")) { fake(); return; } channel = ArgList[0]; message_from(channel, LOG_CRAP); malloc_strcpy(&joined_nick, from); if (!my_stricmp(from, get_server_nickname(from_server))) { int refnum; Window *old_window = curr_scr_win; int switched = 0; if (!in_join_list(channel, from_server)) add_to_join_list(channel, from_server, curr_scr_win->refnum); else { if (curr_scr_win->refnum != (refnum = get_win_from_join_list(channel, from_server))) { switched = 1; set_current_window(get_window_by_refnum(refnum)); } } if (*channel != '+') send_to_server(SERVER(from_server), "MODE %s\r\nMODE %s b", channel, channel, channel); (void) do_hook(JOIN_ME_LIST, "%s", channel); its_me = 1; chan = add_channel(channel, from_server); if (*channel == '+') { got_info(channel, from_server, GOTBANS); got_info(channel, from_server, GOTMODE); } if (switched) set_current_window(old_window); } else { int op = 0, vo = 0; char *c; /* * Workaround for gratuitous protocol change in ef2.9 */ if ((c = strchr(channel, '\007'))) { for (*c++ = 0; *c; c++) { if (*c == 'o') op = 1; else if (*c == 'v') vo = 1; } } chan = add_to_channel(channel, from, from_server, op, vo, FromUserHost, NULL, NULL); } flush_mode_all(chan); user = m_strdup(FromUserHost); host = strchr(user, '@'); *host++ = '\0'; if (check_ignore(from, FromUserHost, channel, IGNORE_JOINS | IGNORE_CRAP, NULL) != IGNORED && chan) { irc_server *irc_serv = NULL; char *tmp2 = NULL; if (get_int_var(AUTO_NSLOOKUP_VAR) && isdigit(*(host + strlen(host) - 1))) tmp2 = do_nslookup(host); message_from(channel, LOG_CRAP); if ((whowas = check_whosplitin_buffer(from, FromUserHost, channel, 0)) && (irc_serv = check_split_server(whowas->server1))) { if (do_hook(LLOOK_JOIN_LIST, "%s %s", irc_serv->name, irc_serv->link)) put_it("%s", convert_output_format(get_format(FORMAT_NETJOIN_FSET), "%s %s %s %d", update_clock(GET_TIME), irc_serv->name, irc_serv->link, 0)); remove_split_server(whowas->server1); } if (do_hook(JOIN_LIST, "%s %s %s", from, channel, tmp2 ? tmp2 : FromUserHost ? FromUserHost : "UnKnown")) { put_it("%s", convert_output_format(get_format(FORMAT_JOIN_FSET), "%s %s %s %s", update_clock(GET_TIME), from, tmp2 ? tmp2 : FromUserHost ? FromUserHost : "UnKnown", channel)); } message_from(NULL, LOG_CRAP); } set_input_prompt(curr_scr_win, get_string_var(INPUT_PROMPT_VAR), 0); update_all_status(curr_scr_win, NULL, 0); notify_mark(from, user, host, 1); new_free(&user); } static void p_invite(char *from, char **ArgList) { char *high; switch (check_ignore(from, FromUserHost, ArgList[1] ? ArgList[1] : NULL, IGNORE_INVITES, NULL)) { case IGNORED: if (get_int_var(SEND_IGNORE_MSG_VAR)) send_to_server(SERVER(from_server), "NOTICE %s :%s is ignoring you", from, get_server_nickname(from_server)); return; case HIGHLIGHTED: high = highlight_char; break; default: high = empty_str; break; } if (ArgList[0] && ArgList[1]) { struct channel *chan = NULL; struct whowas_chan_list *w_chan = NULL; message_from(from, LOG_CRAP); malloc_strcpy(&invite_channel, ArgList[1]); if (check_flooding(from, INVITE_FLOOD, ArgList[1], NULL) && do_hook(INVITE_LIST, "%s %s", from, ArgList[1])) { put_it("%s", convert_output_format(get_format(FORMAT_INVITE_FSET), "%s %s %s", update_clock(GET_TIME), from, ArgList[1])); } if (!(chan = lookup_channel(invite_channel, from_server, 0))) if ((w_chan = check_whowas_chan_buffer(invite_channel, 0))) chan = w_chan->channellist; if (chan && get_int_var(AUTO_REJOIN_VAR) && invite_channel) { if (!in_join_list(invite_channel, from_server)) send_to_server(SERVER(from_server), "JOIN %s %s", invite_channel, ArgList[2] ? ArgList[2] : ""); } malloc_strcpy(&recv_nick, from); } } static void p_silence(char *from, char **ArgList) { char *target = ArgList[0]; char *mag = target++; if (do_hook(SILENCE_LIST, "%c %s", *mag, target)) put_it("%s", convert_output_format(get_format(FORMAT_SILENCE_FSET), "%s %c %s", update_clock(GET_TIME), *mag, target)); } static void p_kill(char *from, char **ArgList) { char sc[20]; int port; int local = 0; port = get_server_port(from_server); if (ArgList[1] && strstr(ArgList[1], get_server_name(from_server))) if (!strchr(from, '.')) local = 1; snprintf(sc, 19, "+%i %d", from_server, port); close_server(from_server, empty_str); clean_whois_queue(); window_check_servers(); set_input_prompt(curr_scr_win, get_string_var(INPUT_PROMPT_VAR), 0); if (strchr(from, '.')) { say("Server [%s] has rejected you (probably due to a nick collision)", from); t_parse_command("SERVER", NULL); } else { if (local && get_int_var(NEXT_SERVER_ON_LOCAL_KILL_VAR)) { int i = from_server + 1; if (i >= number_of_servers) i = 0; snprintf(sc, 19, "+%i", i); from_server = -1; } if (do_hook(DISCONNECT_LIST, "Killed by %s (%s)", from, ArgList[1] ? ArgList[1] : "(No Reason Given)")) put_it("%s", convert_output_format(get_format(FORMAT_KILL_FSET), "%s %s", update_clock(GET_TIME), ArgList[1] ? ArgList[1] : "You have been Killed")); if (get_int_var(AUTO_RECONNECT_VAR)) t_parse_command("SERVER", NULL); } update_all_status(curr_scr_win, NULL, 0); } static void p_ping(char **ArgList) { PasteArgs(ArgList, 0); send_to_server(SERVER(from_server), "PONG %s", ArgList[0]); } static void p_nick(char *from, char **ArgList) { int one_prints = 0, ign = 0, its_me = 0; struct channel *chan; char *line; line = ArgList[0]; if (!my_stricmp(from, get_server_nickname(from_server))) { accept_server_nickname(from_server, line); its_me = 1; user_changing_nickname = 0; } ign = check_ignore(from, FromUserHost, NULL, IGNORE_NICKS | IGNORE_CRAP, NULL); for (chan = server_list[from_server].chan_list; chan; chan = chan->next) { message_from(chan->channel, LOG_CRAP); if (ign != IGNORED && do_hook(CHANNEL_NICK_LIST, "%s %s %s", chan->channel, from, line)) one_prints = 1; } if (one_prints) { if (its_me) { message_from(NULL, LOG_CRAP); } else message_from(what_channel(from, from_server), LOG_CRAP); if (ign != IGNORED && do_hook(NICKNAME_LIST, "%s %s", from, line)) put_it("%s", convert_output_format(get_format (its_me ? FORMAT_NICKNAME_USER_FSET : im_on_channel(what_channel(from, from_server)) ? FORMAT_NICKNAME_FSET : FORMAT_NICKNAME_OTHER_FSET), "%s %s %s %s", update_clock(GET_TIME), from, "-", line)); } rename_nick(from, line, from_server); if (!its_me) { char *user, *host; user = m_strdup(FromUserHost); host = strchr(user, '@'); *host++ = '\0'; notify_mark(from, user, host, 0); notify_mark(line, user, host, 1); new_free(&user); } } static void p_mode(char *from, char **ArgList) { char *channel; char *line; int flag; struct channel *chan = NULL; char buffer[BIG_BUFFER_SIZE + 1]; char *smode; #ifdef COMPRESS_MODES char *tmpbuf = NULL; #endif PasteArgs(ArgList, 1); channel = ArgList[0]; line = ArgList[1]; smode = strchr(from, '.'); flag = check_ignore(from, FromUserHost, channel, (smode ? IGNORE_SMODES : IGNORE_MODES) | IGNORE_CRAP, NULL); message_from(channel, LOG_CRAP); if (channel && line) { strcpy(buffer, line); if (get_int_var(MODE_STRIPPER_VAR)) strip_modes(from, channel, line); if (is_channel(channel)) { #ifdef COMPRESS_MODES chan = (struct channel *) find_in_list((struct list **) &server_list[from_server].chan_list, channel, 0); if (get_int_var(COMPRESS_MODES_VAR)) { tmpbuf = compress_modes(from_server, channel, line); if (tmpbuf) strcpy(line, tmpbuf); else goto end_p_mode; } #endif /* CDE handle mode protection here instead of later */ update_channel_mode(from, channel, from_server, buffer, chan); if (flag != IGNORED && do_hook(MODE_LIST, "%s %s %s", from, channel, line)) put_it("%s", convert_output_format(get_format(smode ? FORMAT_SMODE_FSET : FORMAT_MODE_FSET), "%s %s %s %s %s", update_clock(GET_TIME), from, smode ? "*" : FromUserHost, channel, line)); } else { if (flag != IGNORED && do_hook(MODE_LIST, "%s %s %s", from, channel, line)) { if (!my_stricmp(from, channel)) { if (!my_stricmp(from, get_server_nickname(from_server))) put_it("%s", convert_output_format(get_format(FORMAT_USERMODE_FSET), "%s %s %s %s %s", update_clock(GET_TIME), from, "*", channel, line)); else put_it("%s", convert_output_format(get_format(FORMAT_USERMODE_FSET), "%s %s %s %s %s", update_clock(GET_TIME), from, smode ? "*" : FromUserHost, channel, line)); } else put_it("%s", convert_output_format(get_format(FORMAT_MODE_FSET), "%s %s %s %s %s", update_clock(GET_TIME), from, smode ? "*" : FromUserHost, channel, line)); } update_user_mode(line); } #ifdef COMPRESS_MODES end_p_mode: #endif update_all_status(curr_scr_win, NULL, 0); } message_from(NULL, LOG_CRAP); } static void strip_modes(char *from, char *channel, char *line) { char *mode; char *pointer; char mag = '+'; /* XXXX Bogus */ char *copy = NULL; #ifdef __GNUC__ char free_copy[strlen(line) + 1]; strcpy(free_copy, line); #else char *free_copy = NULL; malloc_strcpy(&free_copy, line); #endif copy = free_copy; mode = next_arg(copy, ©); if (is_channel(channel)) { for (pointer = mode; *pointer; pointer++) { char c = *pointer; switch (c) { case '+': case '-': mag = c; break; case 'l': if (mag == '+') do_hook(MODE_STRIPPED_LIST, "%s %s %c%c %s", from, channel, mag, c, next_arg(copy, ©)); else do_hook(MODE_STRIPPED_LIST, "%s %s %c%c", from, channel, mag, c); break; case 'a': case 'i': case 'm': case 'n': case 'p': case 's': case 't': do_hook(MODE_STRIPPED_LIST, "%s %s %c%c", from, channel, mag, c); break; case 'b': case 'k': case 'o': case 'v': do_hook(MODE_STRIPPED_LIST, "%s %s %c%c %s", from, channel, mag, c, next_arg(copy, ©)); break; } } } else /* User mode */ { for (pointer = mode; *pointer; pointer++) { char c = *pointer; switch (c) { case '+': case '-': mag = c; break; default: do_hook(MODE_STRIPPED_LIST, "%s %s %c%c", from, channel, mag, c); break; } } } #ifndef __GNUC__ new_free(&free_copy); #endif } static void p_kick(char *from, char **ArgList) { char *channel, *who, *comment; char *chankey = NULL; struct channel *chan = NULL; struct nick_list *tmpnick = NULL; int t = 0; channel = ArgList[0]; who = ArgList[1]; comment = ArgList[2] ? ArgList[2] : "(no comment)"; if ((chan = lookup_channel(channel, from_server, CHAN_NOUNLINK))) tmpnick = find_nicklist_in_channellist(from, chan, 0); message_from(channel, LOG_CRAP); if (channel && who && chan) { if (!my_stricmp(who, get_server_nickname(from_server))) { Window *window = chan->window; if (chan->key) malloc_strcpy(&chankey, chan->key); if (get_int_var(AUTO_REJOIN_VAR)) { send_to_server(SERVER(from_server), "JOIN %s %s", channel, chankey ? chankey : empty_str); add_to_join_list(channel, from_server, window ? window->refnum : 0); } new_free(&chankey); remove_channel(channel, from_server); update_all_status(curr_scr_win, NULL, 0); update_input(UPDATE_ALL); if (do_hook(KICK_LIST, "%s %s %s %s", who, from, channel, comment ? comment : empty_str)) put_it("%s", convert_output_format(get_format(FORMAT_KICK_USER_FSET), "%s %s %s %s %s", update_clock(GET_TIME), from, channel, who, comment)); } else { int itsme = 0; itsme = !my_stricmp(get_server_nickname(from_server), from) ? 1 : 0; if ((check_ignore(from, FromUserHost, channel, IGNORE_KICKS | IGNORE_CRAP, NULL) != IGNORED) && do_hook(KICK_LIST, "%s %s %s %s", who, from, channel, comment)) put_it("%s", convert_output_format(get_format(FORMAT_KICK_FSET), "%s %s %s %s %s", update_clock(GET_TIME), from, channel, who, comment)); if (!itsme) { struct nick_list *f_nick = NULL; f_nick = find_nicklist_in_channellist(who, chan, 0); if (chan->chop && tmpnick && is_other_flood(chan, tmpnick, KICK_FLOOD, &t)) { if (get_int_var(KICK_ON_KICKFLOOD_VAR) > get_int_var(DEOP_ON_KICKFLOOD_VAR)) send_to_server(SERVER(from_server), "MODE %s -o %s", chan->channel, from); else if (!f_nick->kickcount++) send_to_server(SERVER(from_server), "KICK %s %s :\002Mass kick detected - (%d kicks in %dsec%s)\002", chan->channel, from, get_int_var(KICK_ON_KICKFLOOD_VAR), t, plural(t)); } } remove_from_channel(channel, who, from_server, 0, NULL); } } update_all_status(curr_scr_win, NULL, 0); message_from(NULL, LOG_CRAP); } static void p_part(char *from, char **ArgList) { char *channel; if (!from || !*from) return; channel = ArgList[0]; PasteArgs(ArgList, 1); message_from(channel, LOG_CRAP); in_on_who = 1; if ((check_ignore(from, FromUserHost, channel, IGNORE_PARTS | IGNORE_CRAP, NULL) != IGNORED) && do_hook(LEAVE_LIST, "%s %s %s %s", from, channel, FromUserHost, ArgList[1] ? ArgList[1] : empty_str)) put_it("%s", convert_output_format(get_format(FORMAT_LEAVE_FSET), "%s %s %s %s %s", update_clock(GET_TIME), from, FromUserHost, channel, ArgList[1] ? ArgList[1] : empty_str)); if (!my_stricmp(from, get_server_nickname(from_server))) { remove_channel(channel, from_server); remove_from_mode_list(channel, from_server); remove_from_join_list(channel, from_server); set_input_prompt(curr_scr_win, get_string_var(INPUT_PROMPT_VAR), 0); } else { remove_from_channel(channel, from, from_server, 0, NULL); } update_all_status(curr_scr_win, NULL, 0); update_input(UPDATE_ALL); message_from(NULL, LOG_CRAP); in_on_who = 0; } static void p_odd(char *from, char *comm, char **ArgList) { PasteArgs(ArgList, 0); if (do_hook(ODD_SERVER_STUFF_LIST, "%s %s %s", from ? from : "*", comm, ArgList[0])) { if (from) say("Odd server stuff: \"%s %s\" (%s)", comm, ArgList[0], from); else say("Odd server stuff: \"%s %s\"", comm, ArgList[0]); } } void parse_server(char *line) { char *from, *comm, *end; int numeric; char **ArgList; char copy[BIG_BUFFER_SIZE + 1]; char *TrueArgs[MAXPARA + 1] = { NULL }; if (!line || !*line) return; end = strlen(line) + line; if (*--end == '\n') *end-- = '\0'; if (*end == '\r') *end-- = '\0'; if (!line || !*line) return; if (*line == ':') { if (!do_hook(RAW_IRC_LIST, "%s", line + 1)) return; } else if (!do_hook(RAW_IRC_LIST, "* %s", line)) return; ArgList = TrueArgs; strncpy(copy, line, BIG_BUFFER_SIZE); FixColorAnsi(line); BreakArgs(line, &from, ArgList, 0); if (!(comm = (*ArgList++)) || !from || !*ArgList) return; /* Empty line from server - ByeBye */ /* * I reformatted these in may '96 by using the output of /stats m * from a few busy servers. They are arranged so that the most * common types are high on the list (to save the average number * of compares.) I will be doing more testing in the future on * a live client to see if this is a reasonable order. */ if ((numeric = atoi(comm))) numbered_command(from, numeric, ArgList); /* There are the core msgs for most non-numeric traffic. */ else if (!strcmp(comm, "PRIVMSG")) p_privmsg(from, ArgList); else if (!strcmp(comm, "JOIN")) p_channel(from, ArgList); else if (!strcmp(comm, "PART")) p_part(from, ArgList); else if (!strcmp(comm, "MODE")) p_mode(from, ArgList); else if (!strcmp(comm, "QUIT")) p_quit(from, ArgList); else if (!strcmp(comm, "NOTICE")) parse_notice(from, ArgList); else if (!strcmp(comm, "NICK")) p_nick(from, ArgList); else if (!strcmp(comm, "TOPIC")) p_topic(from, ArgList); else if (!strcmp(comm, "KICK")) p_kick(from, ArgList); else if (!strcmp(comm, "INVITE")) p_invite(from, ArgList); /* These are used, but not nearly as much as ones above */ else if (!strcmp(comm, "WALLOPS")) p_wallops(from, ArgList); else if (!strcmp(comm, "ERROR")) p_error(from, ArgList); else if (!strcmp(comm, "ERROR:")) p_error(from, ArgList); else if (!strcmp(comm, "SILENCE")) p_silence(from, ArgList); else if (!strcmp(comm, "KILL")) p_kill(from, ArgList); else if (!strcmp(comm, "PONG")) p_pong(from, ArgList); else if (!strcmp(comm, "PING")) p_ping(ArgList); /* Some kind of unrecognized/unsupported command */ else p_odd(from, comm, ArgList); from_server = -1; }