/* * Runs commands in sequential mode. */ char sequential_mode(char **pointers_to_commands, Node *head) { char mode = 's'; pid_t cpid, w; char **command; char return_char = 's'; int i = 0; while (pointers_to_commands[i] != NULL) { command = tokenify(pointers_to_commands[i], " \n\t"); if (command[0] == NULL) { i++; free_tokens(command); continue; } if (handle_exit(command) != 'n') { free_tokens(command); return 'e'; } if (return_char != 'e' && is_mode(command)) { return_char = handle_mode(command, mode, return_char); i++; free_tokens(command); continue; } handle_parallel_builtins(command, NULL, NULL, mode); cpid = fork(); if (cpid == 0) { char *tempcommand; tempcommand = prepend_path(command, head); command[0] = tempcommand; if (execv(command[0], command) < 0) { fprintf(stderr, "execv failed: %s\n", strerror(errno)); printf("That's not a valid command! \n"); free_tokens(command); exit(EXIT_FAILURE); } free(tempcommand); } else { int status = 0; w = wait(&status); i++; } free_tokens(command); } return return_char; }
static void process_named_msg (session *sess, char *type, char *word[], char *word_eol[]) { server *serv = sess->server; char ip[128], nick[NICKLEN]; char *text, *ex; int len = strlen (type); /* fill in the "ip" and "nick" buffers */ ex = strchr (word[1], '!'); if (!ex) /* no '!', must be a server message */ { safe_strcpy (ip, word[1], sizeof (ip)); safe_strcpy (nick, word[1], sizeof (nick)); } else { safe_strcpy (ip, ex + 1, sizeof (ip)); ex[0] = 0; safe_strcpy (nick, word[1], sizeof (nick)); ex[0] = '!'; } if (len == 4) { guint32 t; t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]); /* this should compile to a bunch of: CMP.L, JE ... nice & fast */ switch (t) { case WORDL('J','O','I','N'): { char *chan = word[3]; if (*chan == ':') chan++; if (!serv->p_cmp (nick, serv->nick)) inbound_ujoin (serv, chan, nick, ip); else inbound_join (serv, chan, nick, ip); } return; case WORDL('K','I','C','K'): { char *kicked = word[4]; char *reason = word_eol[5]; if (*kicked) { if (*reason == ':') reason++; if (!strcmp (kicked, serv->nick)) inbound_ukick (serv, word[3], nick, reason); else inbound_kick (serv, word[3], kicked, nick, reason); } } return; case WORDL('K','I','L','L'): EMIT_SIGNAL (XP_TE_KILL, sess, nick, word_eol[5], NULL, NULL, 0); return; case WORDL('M','O','D','E'): handle_mode (serv, word, word_eol, nick, FALSE); /* modes.c */ return; case WORDL('N','I','C','K'): inbound_newnick (serv, nick, (word_eol[3][0] == ':') ? word_eol[3] + 1 : word_eol[3], FALSE); return; case WORDL('P','A','R','T'): { char *chan = word[3]; char *reason = word_eol[4]; if (*chan == ':') chan++; if (*reason == ':') reason++; if (!strcmp (nick, serv->nick)) inbound_upart (serv, chan, ip, reason); else inbound_part (serv, chan, nick, ip, reason); } return; case WORDL('P','O','N','G'): inbound_ping_reply (serv->server_session, (word[4][0] == ':') ? word[4] + 1 : word[4], word[3]); return; case WORDL('Q','U','I','T'): inbound_quit (serv, nick, ip, (word_eol[3][0] == ':') ? word_eol[3] + 1 : word_eol[3]); return; } goto garbage; } else if (len >= 5) { guint32 t; t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]); /* this should compile to a bunch of: CMP.L, JE ... nice & fast */ switch (t) { case WORDL('I','N','V','I'): if (ignore_check (word[1], IG_INVI)) return; if (word[4][0] == ':') EMIT_SIGNAL (XP_TE_INVITED, sess, word[4] + 1, nick, serv->servername, NULL, 0); else EMIT_SIGNAL (XP_TE_INVITED, sess, word[4], nick, serv->servername, NULL, 0); return; case WORDL('N','O','T','I'): { int id = FALSE; /* identified */ text = word_eol[4]; if (*text == ':') text++; if (serv->have_idmsg) { if (*text == '+') { id = TRUE; text++; } else if (*text == '-') text++; } if (!ignore_check (word[1], IG_NOTI)) inbound_notice (serv, word[3], nick, text, ip, id); } return; case WORDL('P','R','I','V'): { char *to = word[3]; int len; int id = FALSE; /* identified */ if (*to) { text = word_eol[4]; if (*text == ':') text++; if (serv->have_idmsg) { if (*text == '+') { id = TRUE; text++; } else if (*text == '-') text++; } len = strlen (text); if (text[0] == 1 && text[len - 1] == 1) /* ctcp */ { text[len - 1] = 0; text++; if (strncasecmp (text, "ACTION", 6) != 0) flood_check (nick, ip, serv, sess, 0); if (strncasecmp (text, "DCC ", 4) == 0) /* redo this with handle_quotes TRUE */ process_data_init (word[1], word_eol[1], word, word_eol, TRUE, FALSE); ctcp_handle (sess, to, nick, ip, text, word, word_eol, id); } else { if (is_channel (serv, to)) { if (ignore_check (word[1], IG_CHAN)) return; inbound_chanmsg (serv, NULL, to, nick, text, FALSE, id); } else { if (ignore_check (word[1], IG_PRIV)) return; inbound_privmsg (serv, nick, ip, text, id); } } } } return; case WORDL('T','O','P','I'): inbound_topicnew (serv, nick, word[3], (word_eol[4][0] == ':') ? word_eol[4] + 1 : word_eol[4]); return; case WORDL('W','A','L','L'): text = word_eol[3]; if (*text == ':') text++; EMIT_SIGNAL (XP_TE_WALLOPS, sess, nick, text, NULL, NULL, 0); return; } } else if (len == 3) { guint32 t; t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]); switch (t) { case WORDL('C','A','P','\0'): if (strncasecmp(word[4], "ACK", 3) == 0) { if (strncasecmp(word[5][0]==':' ? word[5]+1 : word[5], "identify-msg", 12) == 0) { serv->have_idmsg = TRUE; tcp_send_len(serv, "CAP END\r\n", 9); } } else if (strncasecmp(word[4], "LS", 2) == 0) { if (strstr(word_eol[5], "identify-msg") != 0) tcp_send_len(serv, "CAP REQ :identify-msg\r\n", 23); else tcp_send_len(serv, "CAP END\r\n", 9); } else if (strncasecmp(word[4], "NAK",3) == 0) { tcp_send_len(serv, "CAP END\r\n", 9); } return; } } garbage: /* unknown message */ PrintTextf (sess, "GARBAGE: %s\n", word_eol[1]); }
static void process_numeric (session * sess, int n, char *word[], char *word_eol[], char *text) { server *serv = sess->server; /* show whois is the server tab */ session *whois_sess = serv->server_session; /* unless this setting is on */ if (prefs.irc_whois_front) whois_sess = serv->front_session; switch (n) { case 1: inbound_login_start (sess, word[3], word[1]); /* if network is PTnet then you must get your IP address from "001" server message */ if ((strncmp(word[7], "PTnet", 5) == 0) && (strncmp(word[8], "IRC", 3) == 0) && (strncmp(word[9], "Network", 7) == 0) && (strrchr(word[10], '@') != NULL)) { serv->use_who = FALSE; if (prefs.ip_from_server) inbound_foundip (sess, strrchr(word[10], '@')+1); } /* use /NICKSERV */ if (strcasecmp (word[7], "DALnet") == 0 || strcasecmp (word[7], "BRASnet") == 0) serv->nickservtype = 1; /* use /NS */ else if (strcasecmp (word[7], "FreeNode") == 0) serv->nickservtype = 2; goto def; case 4: /* check the ircd type */ serv->use_listargs = FALSE; serv->modes_per_line = 3; /* default to IRC RFC */ if (strncmp (word[5], "bahamut", 7) == 0) /* DALNet */ { serv->use_listargs = TRUE; /* use the /list args */ } else if (strncmp (word[5], "u2.10.", 6) == 0) /* Undernet */ { serv->use_listargs = TRUE; /* use the /list args */ serv->modes_per_line = 6; /* allow 6 modes per line */ } else if (strncmp (word[5], "glx2", 4) == 0) { serv->use_listargs = TRUE; /* use the /list args */ } goto def; case 5: inbound_005 (serv, word); goto def; case 263: /*Server load is temporarily too heavy */ if (fe_is_chanwindow (sess->server)) { fe_chan_list_end (sess->server); fe_message (word_eol[5] + 1, FE_MSG_ERROR); } goto def; case 290: /* CAPAB reply */ if (strstr (word_eol[1], "IDENTIFY-MSG")) { serv->have_idmsg = TRUE; break; } goto def; case 301: inbound_away (serv, word[4], (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5]); break; case 302: if (serv->skip_next_userhost) { char *eq = strchr (word[4], '='); if (eq) { *eq = 0; if (!serv->p_cmp (word[4] + 1, serv->nick)) { char *at = strrchr (eq + 1, '@'); if (at) inbound_foundip (sess, at + 1); } } serv->skip_next_userhost = FALSE; break; } else goto def; case 303: word[4]++; notify_markonline (serv, word); break; case 305: inbound_uback (serv); goto def; case 306: inbound_uaway (serv); goto def; case 312: if (!serv->skip_next_whois) EMIT_SIGNAL (XP_TE_WHOIS3, whois_sess, word[4], word_eol[5], NULL, NULL, 0); else inbound_user_info (sess, NULL, NULL, NULL, word[5], word[4], NULL, 0xff); break; case 311: /* WHOIS 1st line */ serv->inside_whois = 1; inbound_user_info_start (sess, word[4]); if (!serv->skip_next_whois) EMIT_SIGNAL (XP_TE_WHOIS1, whois_sess, word[4], word[5], word[6], word_eol[8] + 1, 0); else inbound_user_info (sess, NULL, word[5], word[6], NULL, word[4], word_eol[8][0] == ':' ? word_eol[8] + 1 : word_eol[8], 0xff); break; case 314: /* WHOWAS */ inbound_user_info_start (sess, word[4]); EMIT_SIGNAL (XP_TE_WHOIS1, whois_sess, word[4], word[5], word[6], word_eol[8] + 1, 0); break; case 317: if (!serv->skip_next_whois) { time_t timestamp = (time_t) atol (word[6]); long idle = atol (word[5]); char *tim; char outbuf[64]; snprintf (outbuf, sizeof (outbuf), "%02ld:%02ld:%02ld", idle / 3600, (idle / 60) % 60, idle % 60); if (timestamp == 0) EMIT_SIGNAL (XP_TE_WHOIS4, whois_sess, word[4], outbuf, NULL, NULL, 0); else { tim = ctime (×tamp); tim[19] = 0; /* get rid of the \n */ EMIT_SIGNAL (XP_TE_WHOIS4T, whois_sess, word[4], outbuf, tim, NULL, 0); } } break; case 318: /* END OF WHOIS */ if (!serv->skip_next_whois) EMIT_SIGNAL (XP_TE_WHOIS6, whois_sess, word[4], NULL, NULL, NULL, 0); serv->skip_next_whois = 0; serv->inside_whois = 0; break; case 313: case 319: if (!serv->skip_next_whois) EMIT_SIGNAL (XP_TE_WHOIS2, whois_sess, word[4], word_eol[5] + 1, NULL, NULL, 0); break; case 307: /* dalnet version */ case 320: /* :is an identified user */ if (!serv->skip_next_whois) EMIT_SIGNAL (XP_TE_WHOIS_ID, whois_sess, word[4], word_eol[5] + 1, NULL, NULL, 0); break; case 321: if (!fe_is_chanwindow (sess->server)) EMIT_SIGNAL (XP_TE_CHANLISTHEAD, serv->server_session, NULL, NULL, NULL, NULL, 0); break; case 322: if (fe_is_chanwindow (sess->server)) { fe_add_chan_list (sess->server, word[4], word[5], word_eol[6] + 1); } else { PrintTextf (serv->server_session, "%-16s %-7d %s\017\n", word[4], atoi (word[5]), word_eol[6] + 1); } break; case 323: if (!fe_is_chanwindow (sess->server)) EMIT_SIGNAL (XP_TE_SERVTEXT, serv->server_session, text, word[1], word[2], NULL, 0); else fe_chan_list_end (sess->server); break; case 324: sess = find_channel (serv, word[4]); if (!sess) sess = serv->server_session; if (sess->ignore_mode) sess->ignore_mode = FALSE; else EMIT_SIGNAL (XP_TE_CHANMODES, sess, word[4], word_eol[5], NULL, NULL, 0); fe_update_mode_buttons (sess, 't', '-'); fe_update_mode_buttons (sess, 'n', '-'); fe_update_mode_buttons (sess, 's', '-'); fe_update_mode_buttons (sess, 'i', '-'); fe_update_mode_buttons (sess, 'p', '-'); fe_update_mode_buttons (sess, 'm', '-'); fe_update_mode_buttons (sess, 'l', '-'); fe_update_mode_buttons (sess, 'k', '-'); handle_mode (serv, word, word_eol, "", TRUE); break; case 329: sess = find_channel (serv, word[4]); if (sess) { if (sess->ignore_date) sess->ignore_date = FALSE; else channel_date (sess, word[4], word[5]); } break; case 330: if (!serv->skip_next_whois) EMIT_SIGNAL (XP_TE_WHOIS_AUTH, whois_sess, word[4], word_eol[6] + 1, word[5], NULL, 0); break; case 332: inbound_topic (serv, word[4], (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5]); break; case 333: inbound_topictime (serv, word[4], word[5], atol (word[6])); break; #if 0 case 338: /* Undernet Real user@host, Real IP */ EMIT_SIGNAL (XP_TE_WHOIS_REALHOST, sess, word[4], word[5], word[6], (word_eol[7][0]==':') ? word_eol[7]+1 : word_eol[7], 0); break; #endif case 341: /* INVITE ACK */ EMIT_SIGNAL (XP_TE_UINVITE, sess, word[4], word[5], serv->servername, NULL, 0); break; case 352: /* WHO */ { unsigned int away = 0; session *who_sess = find_channel (serv, word[4]); if (*word[9] == 'G') away = 1; inbound_user_info (sess, word[4], word[5], word[6], word[7], word[8], word_eol[11], away); /* try to show only user initiated whos */ if (!who_sess || !who_sess->doing_who) EMIT_SIGNAL (XP_TE_SERVTEXT, serv->server_session, text, word[1], word[2], NULL, 0); } break; case 354: /* undernet WHOX: used as a reply for irc_away_status */ { unsigned int away = 0; session *who_sess; /* irc_away_status sends out a "152" */ if (!strcmp (word[4], "152")) { who_sess = find_channel (serv, word[5]); if (*word[7] == 'G') away = 1; /* :SanJose.CA.us.undernet.org 354 z1 152 #zed1 z1 H@ */ inbound_user_info (sess, word[5], 0, 0, 0, word[6], 0, away); /* try to show only user initiated whos */ if (!who_sess || !who_sess->doing_who) EMIT_SIGNAL (XP_TE_SERVTEXT, serv->server_session, text, word[1], word[2], NULL, 0); } else goto def; } break; case 315: /* END OF WHO */ { session *who_sess; who_sess = find_channel (serv, word[4]); if (who_sess) { if (!who_sess->doing_who) EMIT_SIGNAL (XP_TE_SERVTEXT, serv->server_session, text, word[1], word[2], NULL, 0); who_sess->doing_who = FALSE; } else { if (!serv->doing_dns) EMIT_SIGNAL (XP_TE_SERVTEXT, serv->server_session, text, word[1], word[2], NULL, 0); serv->doing_dns = FALSE; } } break; case 348: /* +e-list entry */ if (!inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], TRUE)) goto def; break; case 349: /* end of exemption list */ sess = find_channel (serv, word[4]); if (!sess) { sess = serv->front_session; goto def; } if (!fe_is_banwindow (sess)) goto def; fe_ban_list_end (sess, TRUE); break; case 353: /* NAMES */ inbound_nameslist (serv, word[5], (word_eol[6][0] == ':') ? word_eol[6] + 1 : word_eol[6]); break; case 366: if (!inbound_nameslist_end (serv, word[4])) goto def; break; case 367: /* banlist entry */ inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], FALSE); break; case 368: sess = find_channel (serv, word[4]); if (!sess) { sess = serv->front_session; goto def; } if (!fe_is_banwindow (sess)) goto def; fe_ban_list_end (sess, FALSE); break; case 369: /* WHOWAS end */ case 406: /* WHOWAS error */ EMIT_SIGNAL (XP_TE_SERVTEXT, whois_sess, text, word[1], word[2], NULL, 0); serv->inside_whois = 0; break; case 372: /* motd text */ case 375: /* motd start */ if (!prefs.skipmotd || serv->motd_skipped) EMIT_SIGNAL (XP_TE_MOTD, serv->server_session, text, NULL, NULL, NULL, 0); break; case 376: /* end of motd */ case 422: /* motd file is missing */ inbound_login_end (sess, text); break; case 433: /* nickname in use */ case 432: /* erroneous nickname */ if (serv->end_of_motd) goto def; inbound_next_nick (sess, word[4]); break; case 437: if (serv->end_of_motd || is_channel (serv, word[4])) goto def; inbound_next_nick (sess, word[4]); break; case 471: EMIT_SIGNAL (XP_TE_USERLIMIT, sess, word[4], NULL, NULL, NULL, 0); break; case 473: EMIT_SIGNAL (XP_TE_INVITE, sess, word[4], NULL, NULL, NULL, 0); break; case 474: EMIT_SIGNAL (XP_TE_BANNED, sess, word[4], NULL, NULL, NULL, 0); break; case 475: EMIT_SIGNAL (XP_TE_KEYWORD, sess, word[4], NULL, NULL, NULL, 0); break; case 601: notify_set_offline (serv, word[4], FALSE); break; case 605: notify_set_offline (serv, word[4], TRUE); break; case 600: case 604: notify_set_online (serv, word[4]); break; default: if (serv->inside_whois && word[4][0]) { /* some unknown WHOIS reply, ircd coders make them up weekly */ if (!serv->skip_next_whois) EMIT_SIGNAL (XP_TE_WHOIS_SPECIAL, whois_sess, word[4], (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5], word[2], NULL, 0); return; } def: if (is_channel (serv, word[4])) { session *realsess = find_channel (serv, word[4]); if (!realsess) realsess = serv->server_session; EMIT_SIGNAL (XP_TE_SERVTEXT, realsess, text, word[1], word[2], NULL, 0); } else { EMIT_SIGNAL (XP_TE_SERVTEXT, serv->server_session, text, word[1], word[2], NULL, 0); } } }
void IRC::handle(const string& oline) { string line = trim(oline); printf("%s\n", line.c_str()); //We are pinged, respond! if(line.compare(0, 4, "PING") == 0) { onServerPing(line.substr(5)); return; } char* cstr = new char[line.size() + 1]; strcpy(cstr, line.c_str()); string sender, nick, login, host; bool nickOnly = false; size_t tokn = 0; char *tok = strtok(cstr, " "); while(tok != NULL) { //For each token, check string tmp = tok; if(tokn == 0) { sender = tmp; if(sender[0] == ':') sender = sender.substr(1); size_t exp = sender.find("!"); size_t at = sender.find("@"); //TODO: Add checks for 'exp' and 'at' being string::npos // to avoid calling these when there are (no ill effects // have been seen from not doing so yet, however for sanity sake) if(exp == string::npos || at == string::npos) { nick = trim(sender); login = ""; host = ""; nickOnly = true; } else { nick = trim(sender.substr(0, exp)); login = trim(sender.substr(exp + 1, at)); host = trim(sender.substr(at + 1)); } } if(tokn == 1) { tok = strtok(NULL, " "); string target(tok); //AKA channel uint32_t code = 0; if(tmp.length() == 3 && (code = (uint32_t) atoi(tmp.c_str())) != 0 && code < 1000) { string response = line.substr(sender.length()+5+target.length()+1); handle_numeric(code,target,response); onNumeric(sender,code,target,response); } else if(tmp.compare("PRIVMSG") == 0) { handle_msg(target, nick, login, host, line.substr(line.find(" :") + 2)); } else if(tmp.compare("NOTICE") == 0) { onNotice(target, nick, login, host, line.substr(line.find(" :") + 2)); } else if(tmp.compare("JOIN") == 0) { //TODO: Add this user to the channel. onJoin(target, nick, login, host); } else if(tmp.compare("PART") == 0) { //TODO: Remove this user from the channel. onPart(target, nick, login, host); } else if(tmp.compare("TOPIC") == 0) { onTopic(target, line.substr(line.find(" :") + 2), nick, time(NULL), true); } else if(tmp.compare("KICK") == 0) { tok = strtok(NULL, " "); string recipient(tok); onKick(target, nick, login, host, recipient, line.substr(line.find(" :") + 2)); } else if(tmp.compare("QUIT") == 0) { onQuit(nick, login, host, line.substr(line.find(" :") + 2)); } else if(tmp.compare("MODE") == 0) { tok = strtok(NULL, " "); string mode = tok; if(mode[0] == ':') mode = mode.substr(1); handle_mode(nick, login, host, target, mode); } //TODO: Add mode handler here else { onUnknown(line); } break; } tok = strtok(NULL, " "); ++tokn; } delete[] cstr; }
static void process_numeric (session * sess, int n, char *word[], char *word_eol[], char *text, const message_tags_data *tags_data) { server *serv = sess->server; /* show whois is the server tab */ session *whois_sess = serv->server_session; /* unless this setting is on */ if (prefs.hex_irc_whois_front) whois_sess = serv->front_session; switch (n) { case 1: inbound_login_start (sess, word[3], word[1], tags_data); /* if network is PTnet then you must get your IP address from "001" server message */ if ((strncmp(word[7], "PTnet", 5) == 0) && (strncmp(word[8], "IRC", 3) == 0) && (strncmp(word[9], "Network", 7) == 0) && (strrchr(word[10], '@') != NULL)) { serv->use_who = FALSE; if (prefs.hex_dcc_ip_from_server) inbound_foundip (sess, strrchr(word[10], '@')+1, tags_data); } goto def; case 4: /* check the ircd type */ serv->use_listargs = FALSE; serv->modes_per_line = 3; /* default to IRC RFC */ if (strncmp (word[5], "bahamut", 7) == 0) /* DALNet */ { serv->use_listargs = TRUE; /* use the /list args */ } else if (strncmp (word[5], "u2.10.", 6) == 0) /* Undernet */ { serv->use_listargs = TRUE; /* use the /list args */ serv->modes_per_line = 6; /* allow 6 modes per line */ } else if (strncmp (word[5], "glx2", 4) == 0) { serv->use_listargs = TRUE; /* use the /list args */ } goto def; case 5: inbound_005 (serv, word, tags_data); goto def; case 263: /*Server load is temporarily too heavy */ if (fe_is_chanwindow (sess->server)) { fe_chan_list_end (sess->server); fe_message (word_eol[4], FE_MSG_ERROR); } goto def; case 301: inbound_away (serv, word[4], (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5], tags_data); break; case 302: if (serv->skip_next_userhost) { char *eq = strchr (word[4], '='); if (eq) { *eq = 0; if (!serv->p_cmp (word[4] + 1, serv->nick)) { char *at = strrchr (eq + 1, '@'); if (at) inbound_foundip (sess, at + 1, tags_data); } } serv->skip_next_userhost = FALSE; break; } else goto def; case 303: word[4]++; notify_markonline (serv, word, tags_data); break; case 305: inbound_uback (serv, tags_data); goto def; case 306: inbound_uaway (serv, tags_data); goto def; case 312: if (!serv->skip_next_whois) EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS3, whois_sess, word[4], word_eol[5], NULL, NULL, 0, tags_data->timestamp); else inbound_user_info (sess, NULL, NULL, NULL, word[5], word[4], NULL, NULL, 0xff, tags_data); break; case 311: /* WHOIS 1st line */ serv->inside_whois = 1; inbound_user_info_start (sess, word[4], tags_data); if (!serv->skip_next_whois) EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS1, whois_sess, word[4], word[5], word[6], word_eol[8] + 1, 0, tags_data->timestamp); else inbound_user_info (sess, NULL, word[5], word[6], NULL, word[4], word_eol[8][0] == ':' ? word_eol[8] + 1 : word_eol[8], NULL, 0xff, tags_data); break; case 314: /* WHOWAS */ inbound_user_info_start (sess, word[4], tags_data); EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS1, whois_sess, word[4], word[5], word[6], word_eol[8] + 1, 0, tags_data->timestamp); break; case 317: if (!serv->skip_next_whois) { time_t timestamp = (time_t) atol (word[6]); long idle = atol (word[5]); char *tim; char outbuf[64]; snprintf (outbuf, sizeof (outbuf), "%02ld:%02ld:%02ld", idle / 3600, (idle / 60) % 60, idle % 60); if (timestamp == 0) EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS4, whois_sess, word[4], outbuf, NULL, NULL, 0, tags_data->timestamp); else { tim = ctime (×tamp); tim[19] = 0; /* get rid of the \n */ EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS4T, whois_sess, word[4], outbuf, tim, NULL, 0, tags_data->timestamp); } } break; case 318: /* END OF WHOIS */ if (!serv->skip_next_whois) EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS6, whois_sess, word[4], NULL, NULL, NULL, 0, tags_data->timestamp); serv->skip_next_whois = 0; serv->inside_whois = 0; break; case 313: case 319: if (!serv->skip_next_whois) EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS2, whois_sess, word[4], word_eol[5] + 1, NULL, NULL, 0, tags_data->timestamp); break; case 307: /* dalnet version */ case 320: /* :is an identified user */ if (!serv->skip_next_whois) EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS_ID, whois_sess, word[4], word_eol[5] + 1, NULL, NULL, 0, tags_data->timestamp); break; case 321: if (!fe_is_chanwindow (sess->server)) EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANLISTHEAD, serv->server_session, NULL, NULL, NULL, NULL, 0, tags_data->timestamp); break; case 322: if (fe_is_chanwindow (sess->server)) { fe_add_chan_list (sess->server, word[4], word[5], word_eol[6] + 1); } else { PrintTextTimeStampf (serv->server_session, tags_data->timestamp, "%-16s %-7d %s\017\n", word[4], atoi (word[5]), word_eol[6] + 1); } break; case 323: if (!fe_is_chanwindow (sess->server)) EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text, word[1], word[2], NULL, 0, tags_data->timestamp); else fe_chan_list_end (sess->server); break; case 324: sess = find_channel (serv, word[4]); if (!sess) sess = serv->server_session; if (sess->ignore_mode) sess->ignore_mode = FALSE; else EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANMODES, sess, word[4], word_eol[5], NULL, NULL, 0, tags_data->timestamp); fe_update_mode_buttons (sess, 'c', '-'); fe_update_mode_buttons (sess, 'r', '-'); fe_update_mode_buttons (sess, 't', '-'); fe_update_mode_buttons (sess, 'n', '-'); fe_update_mode_buttons (sess, 'i', '-'); fe_update_mode_buttons (sess, 'm', '-'); fe_update_mode_buttons (sess, 'l', '-'); fe_update_mode_buttons (sess, 'k', '-'); handle_mode (serv, word, word_eol, "", TRUE, tags_data); break; case 328: /* channel url */ sess = find_channel (serv, word[4]); if (sess) { EMIT_SIGNAL_TIMESTAMP (XP_TE_CHANURL, sess, word[4], word[5] + 1, NULL, NULL, 0, tags_data->timestamp); } break; case 329: sess = find_channel (serv, word[4]); if (sess) { if (sess->ignore_date) sess->ignore_date = FALSE; else channel_date (sess, word[4], word[5], tags_data); } break; case 330: if (!serv->skip_next_whois) EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS_AUTH, whois_sess, word[4], word_eol[6] + 1, word[5], NULL, 0, tags_data->timestamp); inbound_user_info (sess, NULL, NULL, NULL, NULL, word[4], NULL, word[5], 0xff, tags_data); break; case 332: inbound_topic (serv, word[4], (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5], tags_data); break; case 333: inbound_topictime (serv, word[4], word[5], atol (word[6]), tags_data); break; #if 0 case 338: /* Undernet Real user@host, Real IP */ EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS_REALHOST, sess, word[4], word[5], word[6], (word_eol[7][0]==':') ? word_eol[7]+1 : word_eol[7], 0, tags_data->timestamp); break; #endif case 341: /* INVITE ACK */ EMIT_SIGNAL_TIMESTAMP (XP_TE_UINVITE, sess, word[4], word[5], serv->servername, NULL, 0, tags_data->timestamp); break; case 352: /* WHO */ { unsigned int away = 0; session *who_sess = find_channel (serv, word[4]); if (*word[9] == 'G') away = 1; inbound_user_info (sess, word[4], word[5], word[6], word[7], word[8], word_eol[11], NULL, away, tags_data); /* try to show only user initiated whos */ if (!who_sess || !who_sess->doing_who) EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text, word[1], word[2], NULL, 0, tags_data->timestamp); } break; case 354: /* undernet WHOX: used as a reply for irc_away_status */ { unsigned int away = 0; session *who_sess; /* irc_away_status and irc_user_list sends out a "152" */ if (!strcmp (word[4], "152")) { who_sess = find_channel (serv, word[5]); if (*word[10] == 'G') away = 1; /* :server 354 yournick 152 #channel ~ident host servname nick H account :realname */ inbound_user_info (sess, word[5], word[6], word[7], word[8], word[9], word_eol[12]+1, word[11], away, tags_data); /* try to show only user initiated whos */ if (!who_sess || !who_sess->doing_who) EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text, word[1], word[2], NULL, 0, tags_data->timestamp); } else goto def; } break; case 315: /* END OF WHO */ { session *who_sess; who_sess = find_channel (serv, word[4]); if (who_sess) { if (!who_sess->doing_who) EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text, word[1], word[2], NULL, 0, tags_data->timestamp); who_sess->doing_who = FALSE; } else { if (!serv->doing_dns) EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, text, word[1], word[2], NULL, 0, tags_data->timestamp); serv->doing_dns = FALSE; } } break; case 346: /* +I-list entry */ if (!inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], 346, tags_data)) goto def; break; case 347: /* end of invite list */ if (!fe_ban_list_end (sess, 347)) goto def; break; case 348: /* +e-list entry */ if (!inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], 348, tags_data)) goto def; break; case 349: /* end of exemption list */ sess = find_channel (serv, word[4]); if (!sess) { sess = serv->front_session; goto def; } if (!fe_ban_list_end (sess, 349)) goto def; break; case 353: /* NAMES */ inbound_nameslist (serv, word[5], (word_eol[6][0] == ':') ? word_eol[6] + 1 : word_eol[6], tags_data); break; case 366: if (!inbound_nameslist_end (serv, word[4], tags_data)) goto def; break; case 367: /* banlist entry */ if (!inbound_banlist (sess, atol (word[7]), word[4], word[5], word[6], 367, tags_data)) goto def; break; case 368: sess = find_channel (serv, word[4]); if (!sess) { sess = serv->front_session; goto def; } if (!fe_ban_list_end (sess, 368)) goto def; break; case 369: /* WHOWAS end */ case 406: /* WHOWAS error */ EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, whois_sess, text, word[1], word[2], NULL, 0, tags_data->timestamp); serv->inside_whois = 0; break; case 372: /* motd text */ case 375: /* motd start */ if (!prefs.hex_irc_skip_motd || serv->motd_skipped) EMIT_SIGNAL_TIMESTAMP (XP_TE_MOTD, serv->server_session, text, NULL, NULL, NULL, 0, tags_data->timestamp); break; case 376: /* end of motd */ case 422: /* motd file is missing */ inbound_login_end (sess, text, tags_data); break; case 432: /* erroneous nickname */ if (serv->end_of_motd) { goto def; } inbound_next_nick (sess, word[4], 1, tags_data); break; case 433: /* nickname in use */ if (serv->end_of_motd) { goto def; } inbound_next_nick (sess, word[4], 0, tags_data); break; case 437: if (serv->end_of_motd || is_channel (serv, word[4])) goto def; inbound_next_nick (sess, word[4], 0, tags_data); break; case 471: EMIT_SIGNAL_TIMESTAMP (XP_TE_USERLIMIT, sess, word[4], NULL, NULL, NULL, 0, tags_data->timestamp); break; case 473: EMIT_SIGNAL_TIMESTAMP (XP_TE_INVITE, sess, word[4], NULL, NULL, NULL, 0, tags_data->timestamp); break; case 474: EMIT_SIGNAL_TIMESTAMP (XP_TE_BANNED, sess, word[4], NULL, NULL, NULL, 0, tags_data->timestamp); break; case 475: EMIT_SIGNAL_TIMESTAMP (XP_TE_KEYWORD, sess, word[4], NULL, NULL, NULL, 0, tags_data->timestamp); break; case 601: notify_set_offline (serv, word[4], FALSE, tags_data); break; case 605: notify_set_offline (serv, word[4], TRUE, tags_data); break; case 600: case 604: notify_set_online (serv, word[4], tags_data); break; case 728: /* +q-list entry */ /* NOTE: FREENODE returns these results inconsistent with e.g. +b */ /* Who else has imlemented MODE_QUIET, I wonder? */ if (!inbound_banlist (sess, atol (word[8]), word[4], word[6], word[7], 728, tags_data)) goto def; break; case 729: /* end of quiet list */ if (!fe_ban_list_end (sess, 729)) goto def; break; case 730: /* RPL_MONONLINE */ notify_set_online_list (serv, word[4] + 1, tags_data); break; case 731: /* RPL_MONOFFLINE */ notify_set_offline_list (serv, word[4] + 1, FALSE, tags_data); break; case 900: /* successful SASL 'logged in as ' */ EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, serv->server_session, word_eol[6]+1, word[1], word[2], NULL, 0, tags_data->timestamp); break; case 903: /* successful SASL auth */ case 904: /* failed SASL auth */ if (inbound_sasl_error (serv)) break; /* might retry */ case 905: /* failed SASL auth */ case 906: /* aborted */ case 907: /* attempting to re-auth after a successful auth */ EMIT_SIGNAL_TIMESTAMP (XP_TE_SASLRESPONSE, serv->server_session, word[1], word[2], word[3], ++word_eol[4], 0, tags_data->timestamp); if (!serv->sent_capend) { serv->sent_capend = TRUE; tcp_send_len (serv, "CAP END\r\n", 9); } break; case 908: /* Supported SASL Mechs */ inbound_sasl_supportedmechs (serv, word[4]); break; default: if (serv->inside_whois && word[4][0]) { /* some unknown WHOIS reply, ircd coders make them up weekly */ if (!serv->skip_next_whois) EMIT_SIGNAL_TIMESTAMP (XP_TE_WHOIS_SPECIAL, whois_sess, word[4], (word_eol[5][0] == ':') ? word_eol[5] + 1 : word_eol[5], word[2], NULL, 0, tags_data->timestamp); return; } def: { session *sess; if (is_channel (serv, word[4])) { sess = find_channel (serv, word[4]); if (!sess) sess = serv->server_session; } else if ((sess=find_dialog (serv,word[4]))) /* user with an open dialog */ ; else sess=serv->server_session; EMIT_SIGNAL_TIMESTAMP (XP_TE_SERVTEXT, sess, text, word[1], word[2], NULL, 0, tags_data->timestamp); } } }
static void process_named_msg (session *sess, char *type, char *word[], char *word_eol[], const message_tags_data *tags_data) { server *serv = sess->server; char ip[128], nick[NICKLEN]; char *text, *ex; int len = strlen (type); /* fill in the "ip" and "nick" buffers */ ex = strchr (word[1], '!'); if (!ex) /* no '!', must be a server message */ { safe_strcpy (ip, word[1], sizeof (ip)); safe_strcpy (nick, word[1], sizeof (nick)); } else { safe_strcpy (ip, ex + 1, sizeof (ip)); ex[0] = 0; safe_strcpy (nick, word[1], sizeof (nick)); ex[0] = '!'; } if (len == 4) { guint32 t; t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]); /* this should compile to a bunch of: CMP.L, JE ... nice & fast */ switch (t) { case WORDL('J','O','I','N'): { char *chan = word[3]; char *account = word[4]; char *realname = word_eol[5]; if (account && strcmp (account, "*") == 0) account = NULL; if (realname && *realname == ':') realname++; if (*chan == ':') chan++; if (!serv->p_cmp (nick, serv->nick)) inbound_ujoin (serv, chan, nick, ip, tags_data); else inbound_join (serv, chan, nick, ip, account, realname, tags_data); } return; case WORDL('K','I','C','K'): { char *kicked = word[4]; char *reason = word_eol[5]; if (*kicked) { if (*reason == ':') reason++; if (!strcmp (kicked, serv->nick)) inbound_ukick (serv, word[3], nick, reason, tags_data); else inbound_kick (serv, word[3], kicked, nick, reason, tags_data); } } return; case WORDL('K','I','L','L'): { char *reason = word_eol[4]; if (*reason == ':') reason++; EMIT_SIGNAL_TIMESTAMP (XP_TE_KILL, sess, nick, reason, NULL, NULL, 0, tags_data->timestamp); } return; case WORDL('M','O','D','E'): handle_mode (serv, word, word_eol, nick, FALSE, tags_data); /* modes.c */ return; case WORDL('N','I','C','K'): inbound_newnick (serv, nick, (word_eol[3][0] == ':') ? word_eol[3] + 1 : word_eol[3], FALSE, tags_data); return; case WORDL('P','A','R','T'): { char *chan = word[3]; char *reason = word_eol[4]; if (*chan == ':') chan++; if (*reason == ':') reason++; if (!strcmp (nick, serv->nick)) inbound_upart (serv, chan, ip, reason, tags_data); else inbound_part (serv, chan, nick, ip, reason, tags_data); } return; case WORDL('P','O','N','G'): inbound_ping_reply (serv->server_session, (word[4][0] == ':') ? word[4] + 1 : word[4], word[3], tags_data); return; case WORDL('Q','U','I','T'): inbound_quit (serv, nick, ip, (word_eol[3][0] == ':') ? word_eol[3] + 1 : word_eol[3], tags_data); return; case WORDL('A','W','A','Y'): inbound_away_notify (serv, nick, (word_eol[3][0] == ':') ? word_eol[3] + 1 : NULL, tags_data); return; } goto garbage; } else if (len >= 5) { guint32 t; t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]); /* this should compile to a bunch of: CMP.L, JE ... nice & fast */ switch (t) { case WORDL('A','C','C','O'): inbound_account (serv, nick, word[3], tags_data); return; case WORDL('I','N','V','I'): if (ignore_check (word[1], IG_INVI)) return; if (word[4][0] == ':') EMIT_SIGNAL_TIMESTAMP (XP_TE_INVITED, sess, word[4] + 1, nick, serv->servername, NULL, 0, tags_data->timestamp); else EMIT_SIGNAL_TIMESTAMP (XP_TE_INVITED, sess, word[4], nick, serv->servername, NULL, 0, tags_data->timestamp); return; case WORDL('N','O','T','I'): { int id = FALSE; /* identified */ text = word_eol[4]; if (*text == ':') { text++; } #ifdef USE_OPENSSL if (!strncmp (text, "CHALLENGE ", 10)) /* QuakeNet CHALLENGE upon our request */ { char *response = challengeauth_response (((ircnet *)serv->network)->user ? ((ircnet *)serv->network)->user : prefs.hex_irc_user_name, serv->password, word[5]); tcp_sendf (serv, "PRIVMSG %s :CHALLENGEAUTH %s %s %s\r\n", CHALLENGEAUTH_NICK, ((ircnet *)serv->network)->user ? ((ircnet *)serv->network)->user : prefs.hex_irc_user_name, response, CHALLENGEAUTH_ALGO); g_free (response); return; /* omit the CHALLENGE <hash> ALGOS message */ } #endif if (serv->have_idmsg) { if (*text == '+') { id = TRUE; text++; } else if (*text == '-') text++; } if (!ignore_check (word[1], IG_NOTI)) inbound_notice (serv, word[3], nick, text, ip, id, tags_data); } return; case WORDL('P','R','I','V'): { char *to = word[3]; int len; int id = FALSE; /* identified */ if (*to) { /* Handle limited channel messages, for now no special event */ if (strchr (serv->chantypes, to[0]) == NULL && strchr (serv->nick_prefixes, to[0]) != NULL) to++; text = word_eol[4]; if (*text == ':') text++; if (serv->have_idmsg) { if (*text == '+') { id = TRUE; text++; } else if (*text == '-') text++; } len = strlen (text); if (text[0] == 1 && text[len - 1] == 1) /* ctcp */ { text[len - 1] = 0; text++; if (g_ascii_strncasecmp (text, "ACTION", 6) != 0) flood_check (nick, ip, serv, sess, 0); if (g_ascii_strncasecmp (text, "DCC ", 4) == 0) /* redo this with handle_quotes TRUE */ process_data_init (word[1], word_eol[1], word, word_eol, TRUE, FALSE); ctcp_handle (sess, to, nick, ip, text, word, word_eol, id, tags_data); } else { if (is_channel (serv, to)) { if (ignore_check (word[1], IG_CHAN)) return; inbound_chanmsg (serv, NULL, to, nick, text, FALSE, id, tags_data); } else { if (ignore_check (word[1], IG_PRIV)) return; inbound_privmsg (serv, nick, ip, text, id, tags_data); } } } } return; case WORDL('T','O','P','I'): inbound_topicnew (serv, nick, word[3], (word_eol[4][0] == ':') ? word_eol[4] + 1 : word_eol[4], tags_data); return; case WORDL('W','A','L','L'): text = word_eol[3]; if (*text == ':') text++; EMIT_SIGNAL_TIMESTAMP (XP_TE_WALLOPS, sess, nick, text, NULL, NULL, 0, tags_data->timestamp); return; } } else if (len == 3) { guint32 t; t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]); switch (t) { case WORDL('C','A','P','\0'): if (strncasecmp (word[4], "ACK", 3) == 0) { inbound_cap_ack (serv, word[1], word[5][0] == ':' ? word_eol[5] + 1 : word_eol[5], tags_data); } else if (strncasecmp (word[4], "LS", 2) == 0) { inbound_cap_ls (serv, word[1], word[5][0] == ':' ? word_eol[5] + 1 : word_eol[5], tags_data); } else if (strncasecmp (word[4], "NAK", 3) == 0) { inbound_cap_nak (serv, tags_data); } else if (strncasecmp (word[4], "LIST", 4) == 0) { inbound_cap_list (serv, word[1], word[5][0] == ':' ? word_eol[5] + 1 : word_eol[5], tags_data); } return; } } garbage: /* unknown message */ PrintTextTimeStampf (sess, tags_data->timestamp, "GARBAGE: %s\n", word_eol[1]); }
/* * Runs commands in parallel mode, with support for background processes. */ char parallel_mode(char **pointers_to_commands, Node *head, Node **paused_list, Node **cpidlist) { int count = 0; // counts the no. of times we've been in the loop; // if more than 1, we need to free // pointers_to_commands, which is different from what we got from main. while (1) { count++; char mode = 'p'; pid_t cpid; char **command; char return_char = 'p'; int i = 0; while (pointers_to_commands[i] != NULL) { command = tokenify(pointers_to_commands[i], " \n\t"); if (command[0] == NULL) { i++; free_tokens(command); continue; } if (handle_exit(command) != 'n') { if (*cpidlist == NULL && pointers_to_commands[i+1] == NULL) { return_char = 'e'; } else { printf("There are processes still running. You cannot exit yet. \n"); } free_tokens(command); i++; continue; } if (is_mode(command)) { return_char = handle_mode(command, mode, return_char); if (return_char == 's') { if (*cpidlist != NULL || pointers_to_commands[i+1] != NULL) { printf("There are processes running. You cannot switch modes yet.\n"); return_char = 'p'; } } free_tokens(command); i++; continue; } if (handle_parallel_builtins(command, paused_list, cpidlist, mode) == 1) { i++; free_tokens(command); continue; } cpid = fork(); if (cpid == 0) { char *tempcommand; tempcommand = prepend_path(command, head); command[0]= tempcommand; if (execv(command[0], command) < 0) { fprintf(stderr, "execv failed: %s\n", strerror(errno)); printf("That's not a valid command! \n"); free_tokens(command); exit(EXIT_FAILURE); } } else { char whole_command[128]; memset(whole_command, '\0', 128); strcat(whole_command, command[0]); if (command[1] != NULL) { strcat(whole_command, " "); strcat(whole_command, command[1]); } char cpidstr[128]; sprintf(cpidstr, "%d", cpid); list_append(cpidstr, whole_command, cpidlist); } i++; free_tokens(command); } if (count > 1) { free_tokens(pointers_to_commands); } if (return_char != 'p') { return return_char; } struct pollfd pfd[1]; pfd[0].fd = 0; pfd[0].events = POLLIN; pfd[0].revents = 0; display_prompt(); int some_process_completed = 0; while (1) { int status; int rv = poll(&pfd[0], 1, 800); Node *to_delete_list = NULL; Node *tempcpidlist = *cpidlist; pid_t w; if (rv == 0) { some_process_completed = 0; while (tempcpidlist != NULL) { w = atoi(tempcpidlist->data); // I know that the ideal way to check for child process death is to use a macro such as WIFEXITED on status, // but it wasn't working for me. // status always had the value 0. So I'm doing this instead to check for process completion. if (waitpid(w, &status, WUNTRACED|WNOHANG) == -1) { list_append(tempcpidlist->data, "", &to_delete_list); printf("\nProcess %s (%s) completed.\n", tempcpidlist->data, tempcpidlist->additional_data); some_process_completed = 1; } tempcpidlist = tempcpidlist->next; } Node *curr = to_delete_list; while (curr != NULL) { list_delete(curr->data, cpidlist); curr = curr->next; } list_clear(to_delete_list); if (some_process_completed == 1) { display_prompt(); } } else if (rv > 0) { char buffer[1024]; if (fgets(buffer, 1024, stdin) == NULL) { if (*cpidlist != NULL) { printf("There are processes still running. You can't exit now.\n"); display_prompt(); } else { return_char = 'e'; return return_char; } } else { char *newbuffer = replace_pound(buffer); newbuffer[strlen(newbuffer)-1] = '\0'; pointers_to_commands = tokenify(newbuffer, ";"); free(newbuffer); break; } } else { printf("there was some kind of error: %s \n", strerror(errno)); } } } }
static void process_named_msg (session *sess, char *type, char *word[], char *word_eol[]) { server *serv = sess->server; char ip[128], nick[NICKLEN]; char *text, *ex; int len = strlen (type); /* fill in the "ip" and "nick" buffers */ ex = strchr (word[1], '!'); if (!ex) /* no '!', must be a server message */ { safe_strcpy (ip, word[1], sizeof (ip)); safe_strcpy (nick, word[1], sizeof (nick)); } else { safe_strcpy (ip, ex + 1, sizeof (ip)); ex[0] = 0; safe_strcpy (nick, word[1], sizeof (nick)); ex[0] = '!'; } if (len == 4) { guint32 t; t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]); /* this should compile to a bunch of: CMP.L, JE ... nice & fast */ switch (t) { case WORDL('J','O','I','N'): { char *chan = word[3]; if (*chan == ':') chan++; if (!serv->p_cmp (nick, serv->nick)) inbound_ujoin (serv, chan, nick, ip); else inbound_join (serv, chan, nick, ip); } return; case WORDL('K','I','C','K'): { char *kicked = word[4]; char *reason = word_eol[5]; if (*kicked) { if (*reason == ':') reason++; if (!strcmp (kicked, serv->nick)) inbound_ukick (serv, word[3], nick, reason); else inbound_kick (serv, word[3], kicked, nick, reason); } } return; case WORDL('K','I','L','L'): EMIT_SIGNAL (XP_TE_KILL, sess, nick, word_eol[5], NULL, NULL, 0); return; case WORDL('M','O','D','E'): handle_mode (serv, word, word_eol, nick, FALSE); /* modes.c */ return; case WORDL('N','I','C','K'): inbound_newnick (serv, nick, (word_eol[3][0] == ':') ? word_eol[3] + 1 : word_eol[3], FALSE); return; case WORDL('P','A','R','T'): { char *chan = word[3]; char *reason = word_eol[4]; if (*chan == ':') chan++; if (*reason == ':') reason++; if (!strcmp (nick, serv->nick)) inbound_upart (serv, chan, ip, reason); else inbound_part (serv, chan, nick, ip, reason); } return; case WORDL('P','O','N','G'): inbound_ping_reply (serv->server_session, (word[4][0] == ':') ? word[4] + 1 : word[4], word[3]); return; case WORDL('Q','U','I','T'): inbound_quit (serv, nick, ip, (word_eol[3][0] == ':') ? word_eol[3] + 1 : word_eol[3]); return; } goto garbage; } else if (len >= 5) { guint32 t; t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]); /* this should compile to a bunch of: CMP.L, JE ... nice & fast */ switch (t) { case WORDL('I','N','V','I'): if (ignore_check (word[1], IG_INVI)) return; if (word[4][0] == ':') EMIT_SIGNAL (XP_TE_INVITED, sess, word[4] + 1, nick, serv->servername, NULL, 0); else EMIT_SIGNAL (XP_TE_INVITED, sess, word[4], nick, serv->servername, NULL, 0); return; case WORDL('N','O','T','I'): { int id = FALSE; /* identified */ text = word_eol[4]; if (*text == ':') text++; if (serv->have_idmsg) { if (*text == '+') { id = TRUE; text++; } else if (*text == '-') text++; } if (!ignore_check (word[1], IG_NOTI)) inbound_notice (serv, word[3], nick, text, ip, id); } return; case WORDL('P','R','I','V'): { char *to = word[3]; int len; int id = FALSE; /* identified */ if (*to) { text = word_eol[4]; if (*text == ':') text++; if (serv->have_idmsg) { if (*text == '+') { id = TRUE; text++; } else if (*text == '-') text++; } len = strlen (text); if (text[0] == 1 && text[len - 1] == 1) /* ctcp */ { text[len - 1] = 0; text++; if (g_ascii_strncasecmp (text, "ACTION", 6) != 0) flood_check (nick, ip, serv, sess, 0); if (g_ascii_strncasecmp (text, "DCC ", 4) == 0) /* redo this with handle_quotes TRUE */ process_data_init (word[1], word_eol[1], word, word_eol, TRUE, FALSE); ctcp_handle (sess, to, nick, ip, text, word, word_eol, id); } else { if (is_channel (serv, to)) { if (ignore_check (word[1], IG_CHAN)) return; inbound_chanmsg (serv, NULL, to, nick, text, FALSE, id); } else { if (ignore_check (word[1], IG_PRIV)) return; inbound_privmsg (serv, nick, ip, text, id); } } } } return; case WORDL('T','O','P','I'): inbound_topicnew (serv, nick, word[3], (word_eol[4][0] == ':') ? word_eol[4] + 1 : word_eol[4]); return; case WORDL('W','A','L','L'): text = word_eol[3]; if (*text == ':') text++; EMIT_SIGNAL (XP_TE_WALLOPS, sess, nick, text, NULL, NULL, 0); return; } } else if (len == 3) { guint32 t; guint32 want_cap; /* format the CAP REQ string based on previous capabilities being requested or not */ guint32 want_sasl; /* CAP END shouldn't be sent when SASL is requested, it needs further responses */ char *pass; /* buffer for SASL password */ char buffer[256]; /* buffer for requesting capabilities and emitting the signal */ t = WORDL((guint8)type[0], (guint8)type[1], (guint8)type[2], (guint8)type[3]); switch (t) { case WORDL('C','A','P','\0'): if (strncasecmp (word[4], "ACK", 3) == 0) { EMIT_SIGNAL (XP_TE_CAPACK, sess->server->server_session, word[1], word[5][0]==':' ? ++word_eol[5] : word_eol[5], NULL, NULL, 0); if (strstr (word_eol[5], "identify-msg") != 0) { serv->have_idmsg = TRUE; } if (strstr (word_eol[5], "multi-prefix") != 0) { serv->have_namesx = TRUE; } if (strstr (word_eol[5], "sasl") != 0) { serv->have_sasl = TRUE; EMIT_SIGNAL (XP_TE_SASLAUTH, serv->server_session, sess->server->sasluser, NULL, NULL, NULL, 0); tcp_send_len (serv, "AUTHENTICATE PLAIN\r\n", 20); pass = encode_sasl_pass (sess->server->sasluser, sess->server->saslpassword); tcp_sendf (sess->server, "AUTHENTICATE %s\r\n", pass); free (pass); } } else if (strncasecmp (word[4], "LS", 2) == 0) { EMIT_SIGNAL (XP_TE_CAPLIST, serv->server_session, word[1], word[5][0]==':' ? ++word_eol[5] : word_eol[5], NULL, NULL, 0); want_cap = 0; want_sasl = 0; if (strstr (word_eol[5], "identify-msg") != 0) { strcpy (buffer, "CAP REQ :identify-msg"); want_cap = 1; } if (strstr (word_eol[5], "multi-prefix") != 0) { want_cap ? strcat (buffer, " multi-prefix") : strcpy (buffer, "CAP REQ :multi-prefix"); want_cap = 1; } /* if the SASL password is set, request SASL auth */ if (strstr (word_eol[5], "sasl") != 0 && strlen (sess->server->saslpassword) != 0) { want_cap ? strcat (buffer, " sasl") : strcpy (buffer, "CAP REQ :sasl"); want_sasl = 1; } if (want_cap) { /* buffer + 9 = emit buffer without "CAP REQ :" */ EMIT_SIGNAL (XP_TE_CAPREQ, sess->server->server_session, buffer + 9, NULL, NULL, NULL, 0); tcp_sendf (serv, "%s\r\n", buffer); } if (!want_sasl) { /* if we use SASL, CAP END is dealt via raw numerics */ tcp_send_len (serv, "CAP END\r\n", 9); } } else if (strncasecmp (word[4], "NAK", 3) == 0) { tcp_send_len (serv, "CAP END\r\n", 9); } return; } } garbage: /* unknown message */ PrintTextf (sess, "GARBAGE: %s\n", word_eol[1]); }