2 * Copyright (C) 2002 Peter Zelezny.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 /* IRC RFC1459(+commonly used extensions) protocol implementation */
45 irc_login (server
*serv
, char *user
, char *realname
)
47 tcp_sendf (serv
, "CAP LS\r\n"); /* start with CAP LS as Charybdis sasl.txt suggests */
49 if (serv
->password
[0] && serv
->loginmethod
== LOGIN_PASS
)
51 tcp_sendf (serv
, "PASS %s\r\n", serv
->password
);
56 "USER %s %s %s :%s\r\n",
57 serv
->nick
, user
, user
, serv
->servername
, realname
);
61 irc_nickserv (server
*serv
, char *cmd
, char *arg1
, char *arg2
, char *arg3
)
63 /* are all ircd authors idiots? */
64 switch (serv
->loginmethod
)
66 case LOGIN_MSG_NICKSERV
:
67 tcp_sendf (serv
, "PRIVMSG NICKSERV :%s %s%s%s\r\n", cmd
, arg1
, arg2
, arg3
);
70 tcp_sendf (serv
, "NICKSERV %s %s%s%s\r\n", cmd
, arg1
, arg2
, arg3
);
74 tcp_sendf (serv
, "PRIVMSG NS :%s %s%s%s\r\n", cmd
, arg1
, arg2
, arg3
);
77 tcp_sendf (serv
, "NS %s %s%s%s\r\n", cmd
, arg1
, arg2
, arg3
);
80 /* why couldn't QuakeNet implement one of the existing ones? */
81 tcp_sendf (serv
, "AUTH %s %s\r\n", arg1
, arg2
);
88 irc_ns_identify (server
*serv
, char *pass
)
90 switch (serv
->loginmethod
)
92 case LOGIN_CHALLENGEAUTH
:
93 tcp_sendf (serv
, "PRIVMSG %s :CHALLENGE\r\n", CHALLENGEAUTH_NICK
); /* request a challenge from Q */
97 irc_nickserv (serv
, "", serv
->nick
, pass
, "");
101 irc_nickserv (serv
, "IDENTIFY", pass
, "", "");
106 irc_ns_ghost (server
*serv
, char *usname
, char *pass
)
108 if (serv
->loginmethod
!= LOGIN_CHALLENGEAUTH
)
110 irc_nickserv (serv
, "GHOST", usname
, " ", pass
);
115 irc_join (server
*serv
, char *channel
, char *key
)
118 tcp_sendf (serv
, "JOIN %s %s\r\n", channel
, key
);
120 tcp_sendf (serv
, "JOIN %s\r\n", channel
);
124 irc_join_list_flush (server
*serv
, GString
*c
, GString
*k
)
126 char *chanstr
, *keystr
;
128 chanstr
= g_string_free (c
, FALSE
);
129 keystr
= g_string_free (k
, FALSE
);
133 tcp_sendf (serv
, "JOIN %s %s\r\n", chanstr
, keystr
);
135 tcp_sendf (serv
, "JOIN %s\r\n", chanstr
);
141 /* join a whole list of channels & keys, split to multiple lines
142 * to get around 512 limit */
145 irc_join_list (server
*serv
, GSList
*channels
, GSList
*keys
)
149 GString
*c
= g_string_new (NULL
);
150 GString
*k
= g_string_new (NULL
);
156 len
= 9; /* "JOIN<space><space>\r\n" */
162 /* measure how many bytes this channel would add... */
165 add
= strlen (clist
->data
);
172 add
+= strlen (klist
->data
);
176 add
++; /* 'x' filler */
182 /* too big? dump buffer and start a fresh one */
185 irc_join_list_flush (serv
, c
, k
);
187 c
= g_string_new (NULL
);
188 k
= g_string_new (NULL
);
193 /* now actually add it to our GStrings */
196 add
= strlen (clist
->data
);
200 g_string_append_c (c
, ',');
202 g_string_append (c
, clist
->data
);
208 add
+= strlen (klist
->data
);
212 g_string_append_c (k
, ',');
214 g_string_append (k
, klist
->data
);
223 g_string_append_c (k
, ',');
225 g_string_append_c (k
, 'x');
235 irc_join_list_flush (serv
, c
, k
);
239 irc_part (server
*serv
, char *channel
, char *reason
)
242 tcp_sendf (serv
, "PART %s :%s\r\n", channel
, reason
);
244 tcp_sendf (serv
, "PART %s\r\n", channel
);
248 irc_quit (server
*serv
, char *reason
)
251 tcp_sendf (serv
, "QUIT :%s\r\n", reason
);
253 tcp_send_len (serv
, "QUIT\r\n", 6);
257 irc_set_back (server
*serv
)
259 tcp_send_len (serv
, "AWAY\r\n", 6);
263 irc_set_away (server
*serv
, char *reason
)
275 tcp_sendf (serv
, "AWAY :%s\r\n", reason
);
279 irc_ctcp (server
*serv
, char *to
, char *msg
)
281 tcp_sendf (serv
, "PRIVMSG %s :\001%s\001\r\n", to
, msg
);
285 irc_nctcp (server
*serv
, char *to
, char *msg
)
287 tcp_sendf (serv
, "NOTICE %s :\001%s\001\r\n", to
, msg
);
291 irc_cycle (server
*serv
, char *channel
, char *key
)
293 tcp_sendf (serv
, "PART %s\r\nJOIN %s %s\r\n", channel
, channel
, key
);
297 irc_kick (server
*serv
, char *channel
, char *nick
, char *reason
)
300 tcp_sendf (serv
, "KICK %s %s :%s\r\n", channel
, nick
, reason
);
302 tcp_sendf (serv
, "KICK %s %s\r\n", channel
, nick
);
306 irc_invite (server
*serv
, char *channel
, char *nick
)
308 tcp_sendf (serv
, "INVITE %s %s\r\n", nick
, channel
);
312 irc_mode (server
*serv
, char *target
, char *mode
)
314 tcp_sendf (serv
, "MODE %s %s\r\n", target
, mode
);
317 /* find channel info when joined */
320 irc_join_info (server
*serv
, char *channel
)
322 tcp_sendf (serv
, "MODE %s\r\n", channel
);
325 /* initiate userlist retreival */
328 irc_user_list (server
*serv
, char *channel
)
331 tcp_sendf (serv
, "WHO %s %%chtsunfra,152\r\n", channel
);
333 tcp_sendf (serv
, "WHO %s\r\n", channel
);
339 irc_userhost (server
*serv
, char *nick
)
341 tcp_sendf (serv
, "USERHOST %s\r\n", nick
);
345 irc_away_status (server
*serv
, char *channel
)
348 tcp_sendf (serv
, "WHO %s %%chtsunfra,152\r\n", channel
);
350 tcp_sendf (serv
, "WHO %s\r\n", channel
);
354 irc_get_ip (server *serv, char *nick)
356 tcp_sendf (serv, "WHO %s\r\n", nick);
362 * Parameters: [<server>] <nickmask>[,<nickmask>[,...]]
365 irc_user_whois (server
*serv
, char *nicks
)
367 tcp_sendf (serv
, "WHOIS %s\r\n", nicks
);
371 irc_message (server
*serv
, char *channel
, char *text
)
373 tcp_sendf (serv
, "PRIVMSG %s :%s\r\n", channel
, text
);
377 irc_action (server
*serv
, char *channel
, char *act
)
379 tcp_sendf (serv
, "PRIVMSG %s :\001ACTION %s\001\r\n", channel
, act
);
383 irc_notice (server
*serv
, char *channel
, char *text
)
385 tcp_sendf (serv
, "NOTICE %s :%s\r\n", channel
, text
);
389 irc_topic (server
*serv
, char *channel
, char *topic
)
392 tcp_sendf (serv
, "TOPIC %s :\r\n", channel
);
394 tcp_sendf (serv
, "TOPIC %s :%s\r\n", channel
, topic
);
396 tcp_sendf (serv
, "TOPIC %s\r\n", channel
);
400 irc_list_channels (server
*serv
, char *arg
, int min_users
)
404 tcp_sendf (serv
, "LIST %s\r\n", arg
);
408 if (serv
->use_listargs
)
409 tcp_sendf (serv
, "LIST >%d,<10000\r\n", min_users
- 1);
411 tcp_send_len (serv
, "LIST\r\n", 6);
415 irc_names (server
*serv
, char *channel
)
417 tcp_sendf (serv
, "NAMES %s\r\n", channel
);
421 irc_change_nick (server
*serv
, char *new_nick
)
423 tcp_sendf (serv
, "NICK %s\r\n", new_nick
);
427 irc_ping (server
*serv
, char *to
, char *timestring
)
430 tcp_sendf (serv
, "PRIVMSG %s :\001PING %s\001\r\n", to
, timestring
);
432 tcp_sendf (serv
, "PING %s\r\n", timestring
);
436 irc_raw (server
*serv
, char *raw
)
443 if (len
< sizeof (tbuf
) - 3)
445 len
= snprintf (tbuf
, sizeof (tbuf
), "%s\r\n", raw
);
446 tcp_send_len (serv
, tbuf
, len
);
449 tcp_send_len (serv
, raw
, len
);
450 tcp_send_len (serv
, "\r\n", 2);
457 /* ============================================================== */
458 /* ======================= IRC INPUT ============================ */
459 /* ============================================================== */
463 channel_date (session
*sess
, char *chan
, char *timestr
)
465 time_t timestamp
= (time_t) atol (timestr
);
466 char *tim
= ctime (×tamp
);
467 tim
[24] = 0; /* get rid of the \n */
468 EMIT_SIGNAL (XP_TE_CHANDATE
, sess
, chan
, tim
, NULL
, NULL
, 0);
472 process_numeric (session
* sess
, int n
,
473 char *word
[], char *word_eol
[], char *text
)
475 server
*serv
= sess
->server
;
476 /* show whois is the server tab */
477 session
*whois_sess
= serv
->server_session
;
479 /* unless this setting is on */
480 if (prefs
.irc_whois_front
)
481 whois_sess
= serv
->front_session
;
488 inbound_login_start (sess
, word
[3], word
[1]);
489 /* if network is PTnet then you must get your IP address
490 from "001" server message */
491 if ((strncmp(word
[7], "PTnet", 5) == 0) &&
492 (strncmp(word
[8], "IRC", 3) == 0) &&
493 (strncmp(word
[9], "Network", 7) == 0) &&
494 (strrchr(word
[10], '@') != NULL
))
496 serv
->use_who
= FALSE
;
497 if (prefs
.ip_from_server
)
498 inbound_foundip (sess
, strrchr(word
[10], '@')+1);
503 case 4: /* check the ircd type */
504 serv
->use_listargs
= FALSE
;
505 serv
->modes_per_line
= 3; /* default to IRC RFC */
506 if (strncmp (word
[5], "bahamut", 7) == 0) /* DALNet */
508 serv
->use_listargs
= TRUE
; /* use the /list args */
509 } else if (strncmp (word
[5], "u2.10.", 6) == 0) /* Undernet */
511 serv
->use_listargs
= TRUE
; /* use the /list args */
512 serv
->modes_per_line
= 6; /* allow 6 modes per line */
513 } else if (strncmp (word
[5], "glx2", 4) == 0)
515 serv
->use_listargs
= TRUE
; /* use the /list args */
520 inbound_005 (serv
, word
);
523 case 263: /*Server load is temporarily too heavy */
524 if (fe_is_chanwindow (sess
->server
))
526 fe_chan_list_end (sess
->server
);
527 fe_message (word_eol
[5] + 1, FE_MSG_ERROR
);
532 inbound_away (serv
, word
[4],
533 (word_eol
[5][0] == ':') ? word_eol
[5] + 1 : word_eol
[5]);
537 if (serv
->skip_next_userhost
)
539 char *eq
= strchr (word
[4], '=');
543 if (!serv
->p_cmp (word
[4] + 1, serv
->nick
))
545 char *at
= strrchr (eq
+ 1, '@');
547 inbound_foundip (sess
, at
+ 1);
551 serv
->skip_next_userhost
= FALSE
;
558 notify_markonline (serv
, word
);
562 inbound_uback (serv
);
566 inbound_uaway (serv
);
570 if (!serv
->skip_next_whois
)
571 EMIT_SIGNAL (XP_TE_WHOIS3
, whois_sess
, word
[4], word_eol
[5], NULL
, NULL
, 0);
573 inbound_user_info (sess
, NULL
, NULL
, NULL
, word
[5], word
[4], NULL
, NULL
, 0xff);
576 case 311: /* WHOIS 1st line */
577 serv
->inside_whois
= 1;
578 inbound_user_info_start (sess
, word
[4]);
579 if (!serv
->skip_next_whois
)
580 EMIT_SIGNAL (XP_TE_WHOIS1
, whois_sess
, word
[4], word
[5],
581 word
[6], word_eol
[8] + 1, 0);
583 inbound_user_info (sess
, NULL
, word
[5], word
[6], NULL
, word
[4],
584 word_eol
[8][0] == ':' ? word_eol
[8] + 1 : word_eol
[8], NULL
, 0xff);
587 case 314: /* WHOWAS */
588 inbound_user_info_start (sess
, word
[4]);
589 EMIT_SIGNAL (XP_TE_WHOIS1
, whois_sess
, word
[4], word
[5],
590 word
[6], word_eol
[8] + 1, 0);
594 if (!serv
->skip_next_whois
)
596 time_t timestamp
= (time_t) atol (word
[6]);
597 long idle
= atol (word
[5]);
601 snprintf (outbuf
, sizeof (outbuf
),
602 "%02ld:%02ld:%02ld", idle
/ 3600, (idle
/ 60) % 60,
605 EMIT_SIGNAL (XP_TE_WHOIS4
, whois_sess
, word
[4],
606 outbuf
, NULL
, NULL
, 0);
609 tim
= ctime (×tamp
);
610 tim
[19] = 0; /* get rid of the \n */
611 EMIT_SIGNAL (XP_TE_WHOIS4T
, whois_sess
, word
[4],
612 outbuf
, tim
, NULL
, 0);
617 case 318: /* END OF WHOIS */
618 if (!serv
->skip_next_whois
)
619 EMIT_SIGNAL (XP_TE_WHOIS6
, whois_sess
, word
[4], NULL
,
621 serv
->skip_next_whois
= 0;
622 serv
->inside_whois
= 0;
627 if (!serv
->skip_next_whois
)
628 EMIT_SIGNAL (XP_TE_WHOIS2
, whois_sess
, word
[4],
629 word_eol
[5] + 1, NULL
, NULL
, 0);
632 case 307: /* dalnet version */
633 case 320: /* :is an identified user */
634 if (!serv
->skip_next_whois
)
635 EMIT_SIGNAL (XP_TE_WHOIS_ID
, whois_sess
, word
[4],
636 word_eol
[5] + 1, NULL
, NULL
, 0);
640 if (!fe_is_chanwindow (sess
->server
))
641 EMIT_SIGNAL (XP_TE_CHANLISTHEAD
, serv
->server_session
, NULL
, NULL
, NULL
, NULL
, 0);
645 if (fe_is_chanwindow (sess
->server
))
647 fe_add_chan_list (sess
->server
, word
[4], word
[5], word_eol
[6] + 1);
650 PrintTextf (serv
->server_session
, "%-16s %-7d %s\017\n",
651 word
[4], atoi (word
[5]), word_eol
[6] + 1);
656 if (!fe_is_chanwindow (sess
->server
))
657 EMIT_SIGNAL (XP_TE_SERVTEXT
, serv
->server_session
, text
, word
[1], word
[2], NULL
, 0);
659 fe_chan_list_end (sess
->server
);
663 sess
= find_channel (serv
, word
[4]);
665 sess
= serv
->server_session
;
666 if (sess
->ignore_mode
)
667 sess
->ignore_mode
= FALSE
;
669 EMIT_SIGNAL (XP_TE_CHANMODES
, sess
, word
[4], word_eol
[5],
671 fe_update_mode_buttons (sess
, 't', '-');
672 fe_update_mode_buttons (sess
, 'n', '-');
673 fe_update_mode_buttons (sess
, 's', '-');
674 fe_update_mode_buttons (sess
, 'i', '-');
675 fe_update_mode_buttons (sess
, 'p', '-');
676 fe_update_mode_buttons (sess
, 'm', '-');
677 fe_update_mode_buttons (sess
, 'l', '-');
678 fe_update_mode_buttons (sess
, 'k', '-');
679 handle_mode (serv
, word
, word_eol
, "", TRUE
);
683 sess
= find_channel (serv
, word
[4]);
686 if (sess
->ignore_date
)
687 sess
->ignore_date
= FALSE
;
689 channel_date (sess
, word
[4], word
[5]);
694 if (!serv
->skip_next_whois
)
695 EMIT_SIGNAL (XP_TE_WHOIS_AUTH
, whois_sess
, word
[4],
696 word_eol
[6] + 1, word
[5], NULL
, 0);
697 inbound_user_info (sess
, NULL
, NULL
, NULL
, NULL
, word
[4], NULL
, word
[5], 0xff);
701 inbound_topic (serv
, word
[4],
702 (word_eol
[5][0] == ':') ? word_eol
[5] + 1 : word_eol
[5]);
706 inbound_topictime (serv
, word
[4], word
[5], atol (word
[6]));
710 case 338: /* Undernet Real user@host, Real IP */
711 EMIT_SIGNAL (XP_TE_WHOIS_REALHOST
, sess
, word
[4], word
[5], word
[6],
712 (word_eol
[7][0]==':') ? word_eol
[7]+1 : word_eol
[7], 0);
716 case 341: /* INVITE ACK */
717 EMIT_SIGNAL (XP_TE_UINVITE
, sess
, word
[4], word
[5], serv
->servername
,
723 unsigned int away
= 0;
724 session
*who_sess
= find_channel (serv
, word
[4]);
729 inbound_user_info (sess
, word
[4], word
[5], word
[6], word
[7],
730 word
[8], word_eol
[11], NULL
, away
);
732 /* try to show only user initiated whos */
733 if (!who_sess
|| !who_sess
->doing_who
)
734 EMIT_SIGNAL (XP_TE_SERVTEXT
, serv
->server_session
, text
, word
[1],
739 case 354: /* undernet WHOX: used as a reply for irc_away_status */
741 unsigned int away
= 0;
744 /* irc_away_status and irc_user_list sends out a "152" */
745 if (!strcmp (word
[4], "152"))
747 who_sess
= find_channel (serv
, word
[5]);
749 if (*word
[10] == 'G')
752 /* :server 354 yournick 152 #channel ~ident host servname nick H account :realname */
753 inbound_user_info (sess
, word
[5], word
[6], word
[7], word
[8],
754 word
[9], word_eol
[12]+1, word
[11], away
);
756 /* try to show only user initiated whos */
757 if (!who_sess
|| !who_sess
->doing_who
)
758 EMIT_SIGNAL (XP_TE_SERVTEXT
, serv
->server_session
, text
,
759 word
[1], word
[2], NULL
, 0);
765 case 315: /* END OF WHO */
768 who_sess
= find_channel (serv
, word
[4]);
771 if (!who_sess
->doing_who
)
772 EMIT_SIGNAL (XP_TE_SERVTEXT
, serv
->server_session
, text
,
773 word
[1], word
[2], NULL
, 0);
774 who_sess
->doing_who
= FALSE
;
777 if (!serv
->doing_dns
)
778 EMIT_SIGNAL (XP_TE_SERVTEXT
, serv
->server_session
, text
,
779 word
[1], word
[2], NULL
, 0);
780 serv
->doing_dns
= FALSE
;
785 case 348: /* +e-list entry */
786 if (!inbound_banlist (sess
, atol (word
[7]), word
[4], word
[5], word
[6], TRUE
))
790 case 349: /* end of exemption list */
791 sess
= find_channel (serv
, word
[4]);
794 sess
= serv
->front_session
;
797 if (!fe_is_banwindow (sess
))
799 fe_ban_list_end (sess
, TRUE
);
802 case 353: /* NAMES */
803 inbound_nameslist (serv
, word
[5],
804 (word_eol
[6][0] == ':') ? word_eol
[6] + 1 : word_eol
[6]);
808 if (!inbound_nameslist_end (serv
, word
[4]))
812 case 367: /* banlist entry */
813 inbound_banlist (sess
, atol (word
[7]), word
[4], word
[5], word
[6], FALSE
);
817 sess
= find_channel (serv
, word
[4]);
820 sess
= serv
->front_session
;
823 if (!fe_is_banwindow (sess
))
825 fe_ban_list_end (sess
, FALSE
);
828 case 369: /* WHOWAS end */
829 case 406: /* WHOWAS error */
830 EMIT_SIGNAL (XP_TE_SERVTEXT
, whois_sess
, text
, word
[1], word
[2], NULL
, 0);
831 serv
->inside_whois
= 0;
834 case 372: /* motd text */
835 case 375: /* motd start */
836 if (!prefs
.skipmotd
|| serv
->motd_skipped
)
837 EMIT_SIGNAL (XP_TE_MOTD
, serv
->server_session
, text
, NULL
, NULL
,
841 case 376: /* end of motd */
842 case 422: /* motd file is missing */
843 inbound_login_end (sess
, text
);
846 case 433: /* nickname in use */
847 case 432: /* erroneous nickname */
848 if (serv
->end_of_motd
)
850 inbound_next_nick (sess
, word
[4]);
854 if (serv
->end_of_motd
|| is_channel (serv
, word
[4]))
856 inbound_next_nick (sess
, word
[4]);
860 EMIT_SIGNAL (XP_TE_USERLIMIT
, sess
, word
[4], NULL
, NULL
, NULL
, 0);
864 EMIT_SIGNAL (XP_TE_INVITE
, sess
, word
[4], NULL
, NULL
, NULL
, 0);
868 EMIT_SIGNAL (XP_TE_BANNED
, sess
, word
[4], NULL
, NULL
, NULL
, 0);
872 EMIT_SIGNAL (XP_TE_KEYWORD
, sess
, word
[4], NULL
, NULL
, NULL
, 0);
876 notify_set_offline (serv
, word
[4], FALSE
);
880 notify_set_offline (serv
, word
[4], TRUE
);
885 notify_set_online (serv
, word
[4]);
888 case 730: /* RPL_MONONLINE */
889 ex
= strchr (word
[4], '!'); /* only send the nick */
892 notify_set_online (serv
, word
[4] + 1);
895 case 731: /* RPL_MONOFFLINE */
896 ex
= strchr (word
[4], '!'); /* only send the nick */
899 notify_set_offline (serv
, word
[4] + 1, FALSE
);
902 case 900: /* successful SASL 'logged in as ' */
903 EMIT_SIGNAL (XP_TE_SERVTEXT
, serv
->server_session
, word_eol
[6]+1, word
[1], word
[2], NULL
, 0);
905 case 903: /* successful SASL auth */
906 case 904: /* aborted SASL auth */
907 case 905: /* failed SASL auth */
908 case 906: /* registration completes before SASL auth */
909 case 907: /* attempting to re-auth after a successful auth */
910 EMIT_SIGNAL (XP_TE_SASLRESPONSE
, serv
->server_session
, word
[1], word
[2], word
[3], ++word_eol
[4], 0);
911 tcp_send_len (serv
, "CAP END\r\n", 9);
916 if (serv
->inside_whois
&& word
[4][0])
918 /* some unknown WHOIS reply, ircd coders make them up weekly */
919 if (!serv
->skip_next_whois
)
920 EMIT_SIGNAL (XP_TE_WHOIS_SPECIAL
, whois_sess
, word
[4],
921 (word_eol
[5][0] == ':') ? word_eol
[5] + 1 : word_eol
[5],
927 if (is_channel (serv
, word
[4]))
929 session
*realsess
= find_channel (serv
, word
[4]);
931 realsess
= serv
->server_session
;
932 EMIT_SIGNAL (XP_TE_SERVTEXT
, realsess
, text
, word
[1], word
[2], NULL
, 0);
935 EMIT_SIGNAL (XP_TE_SERVTEXT
, serv
->server_session
, text
, word
[1],
941 /* handle named messages that starts with a ':' */
944 process_named_msg (session
*sess
, char *type
, char *word
[], char *word_eol
[])
946 server
*serv
= sess
->server
;
947 char ip
[128], nick
[NICKLEN
];
949 int len
= strlen (type
);
951 /* fill in the "ip" and "nick" buffers */
952 ex
= strchr (word
[1], '!');
953 if (!ex
) /* no '!', must be a server message */
955 safe_strcpy (ip
, word
[1], sizeof (ip
));
956 safe_strcpy (nick
, word
[1], sizeof (nick
));
959 safe_strcpy (ip
, ex
+ 1, sizeof (ip
));
961 safe_strcpy (nick
, word
[1], sizeof (nick
));
969 t
= WORDL((guint8
)type
[0], (guint8
)type
[1], (guint8
)type
[2], (guint8
)type
[3]);
970 /* this should compile to a bunch of: CMP.L, JE ... nice & fast */
974 case WORDL('A','C','C','O'):
975 inbound_account (serv
, nick
, word
[3]);
978 case WORDL('J','O','I','N'):
980 char *chan
= word
[3];
981 char *account
= word
[4];
982 char *realname
= word_eol
[5] + 1;
986 if (!serv
->p_cmp (nick
, serv
->nick
))
987 inbound_ujoin (serv
, chan
, nick
, ip
);
989 inbound_join (serv
, chan
, nick
, ip
, account
, realname
);
993 case WORDL('K','I','C','K'):
995 char *kicked
= word
[4];
996 char *reason
= word_eol
[5];
1001 if (!strcmp (kicked
, serv
->nick
))
1002 inbound_ukick (serv
, word
[3], nick
, reason
);
1004 inbound_kick (serv
, word
[3], kicked
, nick
, reason
);
1009 case WORDL('K','I','L','L'):
1010 EMIT_SIGNAL (XP_TE_KILL
, sess
, nick
, word_eol
[5], NULL
, NULL
, 0);
1013 case WORDL('M','O','D','E'):
1014 handle_mode (serv
, word
, word_eol
, nick
, FALSE
); /* modes.c */
1017 case WORDL('N','I','C','K'):
1018 inbound_newnick (serv
, nick
, (word_eol
[3][0] == ':')
1019 ? word_eol
[3] + 1 : word_eol
[3], FALSE
);
1022 case WORDL('P','A','R','T'):
1024 char *chan
= word
[3];
1025 char *reason
= word_eol
[4];
1031 if (!strcmp (nick
, serv
->nick
))
1032 inbound_upart (serv
, chan
, ip
, reason
);
1034 inbound_part (serv
, chan
, nick
, ip
, reason
);
1038 case WORDL('P','O','N','G'):
1039 inbound_ping_reply (serv
->server_session
,
1040 (word
[4][0] == ':') ? word
[4] + 1 : word
[4], word
[3]);
1043 case WORDL('Q','U','I','T'):
1044 inbound_quit (serv
, nick
, ip
,
1045 (word_eol
[3][0] == ':') ? word_eol
[3] + 1 : word_eol
[3]);
1048 case WORDL('A','W','A','Y'):
1049 inbound_away_notify (serv
, nick
,
1050 (word_eol
[3][0] == ':') ? word_eol
[3] + 1 : NULL
);
1060 t
= WORDL((guint8
)type
[0], (guint8
)type
[1], (guint8
)type
[2], (guint8
)type
[3]);
1063 case WORDL('C','A','P','\0'):
1064 if (strncasecmp (word
[4], "ACK", 3) == 0)
1066 inbound_cap_ack (serv
, word
[1],
1067 word
[5][0] == ':' ? word_eol
[5] + 1 : word_eol
[5]);
1069 else if (strncasecmp (word
[4], "LS", 2) == 0)
1071 inbound_cap_ls (serv
, word
[1],
1072 word
[5][0] == ':' ? word_eol
[5] + 1 : word_eol
[5]);
1074 else if (strncasecmp (word
[4], "NAK", 3) == 0)
1076 inbound_cap_nak (serv
);
1078 else if (strncasecmp (word
[4], "LIST", 4) == 0)
1080 inbound_cap_list (serv
, word
[1],
1081 word
[5][0] == ':' ? word_eol
[5] + 1 : word_eol
[5]);
1093 t
= WORDL((guint8
)type
[0], (guint8
)type
[1], (guint8
)type
[2], (guint8
)type
[3]);
1094 /* this should compile to a bunch of: CMP.L, JE ... nice & fast */
1097 case WORDL('I','N','V','I'):
1098 if (ignore_check (word
[1], IG_INVI
))
1101 if (word
[4][0] == ':')
1102 EMIT_SIGNAL (XP_TE_INVITED
, sess
, word
[4] + 1, nick
,
1103 serv
->servername
, NULL
, 0);
1105 EMIT_SIGNAL (XP_TE_INVITED
, sess
, word
[4], nick
,
1106 serv
->servername
, NULL
, 0);
1110 case WORDL('N','O','T','I'):
1121 if (!strncmp (text
, "CHALLENGE ", 10)) /* QuakeNet CHALLENGE upon our request */
1123 response
= challengeauth_response (((ircnet
*)serv
->network
)->user
? ((ircnet
*)serv
->network
)->user
: prefs
.username
, serv
->password
, word
[5]);
1125 tcp_sendf (serv
, "PRIVMSG %s :CHALLENGEAUTH %s %s %s\r\n",
1127 ((ircnet
*)serv
->network
)->user
? ((ircnet
*)serv
->network
)->user
: prefs
.username
,
1129 CHALLENGEAUTH_ALGO
);
1132 return; /* omit the CHALLENGE <hash> ALGOS message */
1135 if (serv
->have_idmsg
)
1141 } else if (*text
== '-')
1145 if (!ignore_check (word
[1], IG_NOTI
))
1146 inbound_notice (serv
, word
[3], nick
, text
, ip
, id
);
1150 case WORDL('P','R','I','V'):
1154 int id
= FALSE
; /* identified */
1160 if (serv
->have_idmsg
)
1166 } else if (*text
== '-')
1169 len
= strlen (text
);
1170 if (text
[0] == 1 && text
[len
- 1] == 1) /* ctcp */
1174 if (strncasecmp (text
, "ACTION", 6) != 0)
1175 flood_check (nick
, ip
, serv
, sess
, 0);
1176 if (strncasecmp (text
, "DCC ", 4) == 0)
1177 /* redo this with handle_quotes TRUE */
1178 process_data_init (word
[1], word_eol
[1], word
, word_eol
, TRUE
, FALSE
);
1179 ctcp_handle (sess
, to
, nick
, ip
, text
, word
, word_eol
, id
);
1182 if (is_channel (serv
, to
))
1184 if (ignore_check (word
[1], IG_CHAN
))
1186 inbound_chanmsg (serv
, NULL
, to
, nick
, text
, FALSE
, id
);
1189 if (ignore_check (word
[1], IG_PRIV
))
1191 inbound_privmsg (serv
, nick
, ip
, text
, id
);
1198 case WORDL('T','O','P','I'):
1199 inbound_topicnew (serv
, nick
, word
[3],
1200 (word_eol
[4][0] == ':') ? word_eol
[4] + 1 : word_eol
[4]);
1203 case WORDL('W','A','L','L'):
1207 EMIT_SIGNAL (XP_TE_WALLOPS
, sess
, nick
, text
, NULL
, NULL
, 0);
1213 /* unknown message */
1214 PrintTextf (sess
, "GARBAGE: %s\n", word_eol
[1]);
1217 /* handle named messages that DON'T start with a ':' */
1220 process_named_servermsg (session
*sess
, char *buf
, char *rawname
, char *word_eol
[])
1222 sess
= sess
->server
->server_session
;
1224 if (!strncmp (buf
, "PING ", 5))
1226 tcp_sendf (sess
->server
, "PONG %s\r\n", buf
+ 5);
1229 if (!strncmp (buf
, "ERROR", 5))
1231 EMIT_SIGNAL (XP_TE_SERVERERROR
, sess
, buf
+ 7, NULL
, NULL
, NULL
, 0);
1234 if (!strncmp (buf
, "NOTICE ", 7))
1239 EMIT_SIGNAL (XP_TE_SERVNOTICE
, sess
, buf
, sess
->server
->servername
, NULL
, NULL
, 0);
1242 if (!strncmp (buf
, "AUTHENTICATE +", 14)) /* omit SASL "empty" responses */
1247 EMIT_SIGNAL (XP_TE_SERVTEXT
, sess
, buf
, sess
->server
->servername
, rawname
, NULL
, 0);
1250 /* irc_inline() - 1 single line received from serv */
1253 irc_inline (server
*serv
, char *buf
, int len
)
1255 session
*sess
, *tmp
;
1257 char *word
[PDIWORDS
+1];
1258 char *word_eol
[PDIWORDS
+1];
1259 char pdibuf_static
[522]; /* 1 line can potentially be 512*6 in utf8 */
1260 char *pdibuf
= pdibuf_static
;
1262 url_check_line (buf
, len
);
1264 /* need more than 522? fall back to malloc */
1265 if (len
>= sizeof (pdibuf_static
))
1266 pdibuf
= malloc (len
+ 1);
1268 sess
= serv
->front_session
;
1270 /* Python relies on this */
1271 word
[PDIWORDS
] = NULL
;
1272 word_eol
[PDIWORDS
] = NULL
;
1276 /* split line into words and words_to_end_of_line */
1277 process_data_init (pdibuf
, buf
, word
, word_eol
, FALSE
, FALSE
);
1279 /* find a context for this message */
1280 if (is_channel (serv
, word
[3]))
1282 tmp
= find_channel (serv
, word
[3]);
1287 /* for server messages, the 2nd word is the "message type" */
1291 word_eol
[1] = buf
; /* keep the ":" for plugins */
1292 if (plugin_emit_server (sess
, type
, word
, word_eol
))
1295 word_eol
[1] = buf
+ 1; /* but not for xchat internally */
1299 process_data_init (pdibuf
, buf
, word
, word_eol
, FALSE
, FALSE
);
1300 word
[0] = type
= word
[1];
1301 if (plugin_emit_server (sess
, type
, word
, word_eol
))
1307 process_named_servermsg (sess
, buf
, word
[0], word_eol
);
1311 /* see if the second word is a numeric */
1312 if (isdigit ((unsigned char) word
[2][0]))
1318 process_numeric (sess
, atoi (word
[2]), word
, word_eol
, text
);
1321 process_named_msg (sess
, type
, word
, word_eol
);
1325 if (pdibuf
!= pdibuf_static
)
1330 proto_fill_her_up (server
*serv
)
1332 serv
->p_inline
= irc_inline
;
1333 serv
->p_invite
= irc_invite
;
1334 serv
->p_cycle
= irc_cycle
;
1335 serv
->p_ctcp
= irc_ctcp
;
1336 serv
->p_nctcp
= irc_nctcp
;
1337 serv
->p_quit
= irc_quit
;
1338 serv
->p_kick
= irc_kick
;
1339 serv
->p_part
= irc_part
;
1340 serv
->p_ns_identify
= irc_ns_identify
;
1341 serv
->p_ns_ghost
= irc_ns_ghost
;
1342 serv
->p_join
= irc_join
;
1343 serv
->p_join_list
= irc_join_list
;
1344 serv
->p_login
= irc_login
;
1345 serv
->p_join_info
= irc_join_info
;
1346 serv
->p_mode
= irc_mode
;
1347 serv
->p_user_list
= irc_user_list
;
1348 serv
->p_away_status
= irc_away_status
;
1349 /*serv->p_get_ip = irc_get_ip;*/
1350 serv
->p_whois
= irc_user_whois
;
1351 serv
->p_get_ip
= irc_user_list
;
1352 serv
->p_get_ip_uh
= irc_userhost
;
1353 serv
->p_set_back
= irc_set_back
;
1354 serv
->p_set_away
= irc_set_away
;
1355 serv
->p_message
= irc_message
;
1356 serv
->p_action
= irc_action
;
1357 serv
->p_notice
= irc_notice
;
1358 serv
->p_topic
= irc_topic
;
1359 serv
->p_list_channels
= irc_list_channels
;
1360 serv
->p_change_nick
= irc_change_nick
;
1361 serv
->p_names
= irc_names
;
1362 serv
->p_ping
= irc_ping
;
1363 serv
->p_raw
= irc_raw
;
1364 serv
->p_cmp
= rfc_casecmp
; /* can be changed by 005 in modes.c */