home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / yagirc-0.51.tar.gz / yagirc-0.51.tar / yagirc-0.51 / events-named.c < prev    next >
C/C++ Source or Header  |  1998-05-09  |  17KB  |  599 lines

  1. /*
  2.  
  3.  events-named.c : Functions to handle (named) IRC server replies
  4.  
  5.     Copyright (C) 1998 Timo Sirainen
  6.  
  7.     This program is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License as published by
  9.     the Free Software Foundation; either version 2 of the License, or
  10.     (at your option) any later version.
  11.  
  12.     This program is distributed in the hope that it will be useful,
  13.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.     GNU General Public License for more details.
  16.  
  17.     You should have received a copy of the GNU General Public License
  18.     along with this program; if not, write to the Free Software
  19.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21.  
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <ctype.h>
  25.  
  26. #include <glib.h>
  27.  
  28. #include "os.h"
  29. #include "irc.h"
  30. #include "txt.h"
  31. #include "gui.h"
  32. #include "ctcp.h"
  33. #include "events.h"
  34.  
  35. char *esendnick, *esendaddr;
  36. SERVER_REC *eserver;
  37. WINDOW_REC *edefwin;
  38.  
  39. typedef int (*CALL_FUNC)(char *, char *, char *);
  40.  
  41. struct CMD_STRUCT
  42. {
  43.     char *name;
  44.     CALL_FUNC func;
  45. } CMD_STRUCT;
  46.  
  47. static struct CMD_STRUCT ctcp_cmds[] =
  48. {
  49.     { "VERSION", (CALL_FUNC) ctcp_version },
  50.     { "PING", (CALL_FUNC) ctcp_ping },
  51.     { "ACTION", (CALL_FUNC) ctcp_action },
  52.     { "DCC", (CALL_FUNC) ctcp_dcc },
  53.     { NULL, NULL }
  54. };
  55.  
  56. /* Remove nick from list */
  57. static void remove_nick(CHAN_REC *chan, char *nick)
  58. {
  59.     char *data;
  60.     GList *tmp;
  61.  
  62.     g_return_if_fail(chan != NULL);
  63.     g_return_if_fail(nick != NULL);
  64.  
  65.     tmp = g_list_first(chan->nicks);
  66.     while (tmp != NULL)
  67.     {
  68.         data = (char *) tmp->data;
  69.         if (strcasecmp(isircflag(*data) ? data+1 : data, nick) == 0)
  70.         {
  71.             g_free(tmp->data);
  72.             chan->nicks = g_list_remove_link(chan->nicks, tmp);
  73.             break;
  74.         }
  75.         tmp = tmp->next;
  76.     }
  77. }
  78.  
  79. /* Change nick mode in list */
  80. static void nick_mode_change(CHAN_REC *chan, char *nick, char mode)
  81. {
  82.     char *data;
  83.     GList *tmp;
  84.  
  85.     g_return_if_fail(chan != NULL);
  86.     g_return_if_fail(nick != NULL);
  87.  
  88.     tmp = g_list_first(chan->nicks);
  89.     while (tmp != NULL)
  90.     {
  91.         data = (char *) tmp->data;
  92.         if (strcasecmp(isircflag(*data) ? data+1 : data, nick) == 0)
  93.         {
  94.             /* remove old nick from list */
  95.             g_free(tmp->data);
  96.             chan->nicks = g_list_remove_link(chan->nicks, tmp);
  97.  
  98.             /* insert new nick to list */
  99.             data = g_malloc(strlen(nick)+1);
  100.             if (mode != ' ')
  101.                 sprintf(data, "%c%s", mode, nick);
  102.             else
  103.                 strcpy(data, nick);
  104.             chan->nicks = g_list_insert_sorted(chan->nicks, data, (GCompareFunc) irc_nicks_compare);
  105.             break;
  106.         }
  107.         tmp = tmp->next;
  108.     }
  109. }
  110.  
  111. /* Change nick name in list */
  112. static void change_nick(CHAN_REC *chan, char *oldnick, char *newnick)
  113. {
  114.     char *data, mode;
  115.     GList *tmp;
  116.  
  117.     g_return_if_fail(chan != NULL);
  118.     g_return_if_fail(oldnick != NULL);
  119.     g_return_if_fail(newnick != NULL);
  120.  
  121.     tmp = g_list_first(chan->nicks);
  122.     while (tmp != NULL)
  123.     {
  124.         data = (char *) tmp->data;
  125.         if (strcasecmp(isircflag(*data) ? data+1 : data, oldnick) == 0)
  126.         {
  127.             mode = isircflag(*data) ? *data : ' ';
  128.             /* remove old nick from list */
  129.             g_free(tmp->data);
  130.             chan->nicks = g_list_remove_link(chan->nicks, tmp);
  131.  
  132.             /* insert new nick to list */
  133.             data = g_malloc(strlen(newnick)+1);
  134.             if (mode != ' ')
  135.                 sprintf(data, "%c%s", mode, newnick);
  136.             else
  137.                 strcpy(data, newnick);
  138.             chan->nicks = g_list_insert_sorted(chan->nicks, data, (GCompareFunc) irc_nicks_compare);
  139.             break;
  140.         }
  141.         tmp = tmp->next;
  142.     }
  143. }
  144.  
  145. void eirc_privmsg(char *data)
  146. {
  147.     char *channame;
  148.     CHAN_REC *chan;
  149.  
  150.     g_return_if_fail(data != NULL);
  151.  
  152.     channame = event_get_param(&data); /* Channel or nick name */
  153.     if (*data == ':') data++;
  154.  
  155.     if (esendnick == NULL) esendnick = "!server!";
  156.  
  157.     if (*data == 1)
  158.     {
  159.         /* ctcp message */
  160.         char *ptr;
  161.         int n, ret;
  162.  
  163.         if (irc_is_ignored(esendnick, IGNORE_CTCP)) return;
  164.  
  165.         /* remove the later \001 */
  166.         ptr = strchr(++data, 1);
  167.         if (ptr != NULL)
  168.             *ptr = *(ptr+1) == '\0' ? '\0' : ' ';
  169.  
  170.         /* skip "CTCP" */
  171.         for (ptr = data; *ptr != ' ' && *ptr != '\0'; ptr++) ;
  172.         if (*ptr == ' ') *ptr++ = '\0';
  173.  
  174.         ret = 2;
  175.         for (n = 0; ctcp_cmds[n].name != NULL; n++)
  176.         {
  177.             if (strcasecmp(ctcp_cmds[n].name, data) == 0)
  178.             {
  179.                 ret = ctcp_cmds[n].func(esendnick, channame, ptr);
  180.                 break;
  181.             }
  182.         }
  183.  
  184.         if (ret)
  185.         {
  186.             drawtext(edefwin, TXT_TYPE_DEFAULT, "%9>>> %_%s%_ requested %s%!%_%s%_%! from %_%s\n", esendnick,
  187.                      ret == 1 ? "" : "unknown ctcp ", data, channame);
  188.         }
  189.         return;
  190.     }
  191.  
  192.     if (channame[0] == '#' || channame[0] == '&')
  193.     {
  194.         /* message to some channel */
  195.         char *nick;
  196.         int nicklen;
  197.         WINDOW_REC *win;
  198.  
  199.         if (irc_is_ignored(esendnick, IGNORE_PUBLIC)) return;
  200.  
  201.         chan = channel_joined(eserver, channame);
  202.         nick = chan != NULL ? chan->server->nick : eserver->nick;
  203.         nicklen = strlen(nick);
  204.         win = chan == NULL ? edefwin : chan->window;
  205.         if (strncasecmp(data, nick, nicklen) == 0 && !isalnum(data[nicklen]))
  206.         {
  207.             /* found your nick at the start of the line */
  208.             if (chan != NULL && strcasecmp(channame, chan->window->curchan->name) == 0)
  209.                 drawtext(win, TXT_TYPE_DEFAULT, "<%1%s%n> %s\n", esendnick, data); /* message sent in this channel */
  210.             else
  211.                 drawtext(win, TXT_TYPE_DEFAULT, "<%1%s%n:%2%s%n> %s\n", esendnick, channame, data); /* message sent to some other channel */
  212.         }
  213.         else
  214.         {
  215.             if (chan != NULL && strcasecmp(channame, chan->window->curchan->name) == 0)
  216.                 drawtext(win, TXT_TYPE_DEFAULT, "<%s> %s\n", esendnick, data); /* message sent in this channel */
  217.             else
  218.                 drawtext(win, TXT_TYPE_DEFAULT, "<%s:%2%s%n> %s\n", esendnick, channame, data); /* message sent to some other channel */
  219.         }
  220.     }
  221.     else
  222.     {
  223.         /* private message */
  224.         if (irc_is_ignored(esendnick, IGNORE_PRIVATE)) return;
  225.         chan = channel_joined(eserver, esendnick);
  226.         drawtext(chan == NULL ? edefwin : chan->window, TXT_TYPE_DEFAULT,
  227.                  "[%3%s%n(%4%s%n)]%n %s\n",
  228.                  esendnick, esendaddr == NULL ? "" : esendaddr, data);
  229.     }
  230.  
  231.     if (chan != NULL && !chan->new_data && chan->window != curwin)
  232.     {
  233.         chan->new_data = 1;
  234.         gui_channel_hilight(chan);
  235.     }
  236. }
  237.  
  238. void eirc_notice(char *data)
  239. {
  240.     char *channame;
  241.     CHAN_REC *chan;
  242.  
  243.     g_return_if_fail(data != NULL);
  244.  
  245.     channame = event_get_param(&data); /* Channel or nick name */
  246.     if (*data == ':') data++; /* notice text */
  247.  
  248.     if (esendnick == NULL) esendnick = "server";
  249.  
  250.     if (*data == 1)
  251.     {
  252.         /* ctcp reply */
  253.         char *ptr;
  254.  
  255.         ptr = strchr(++data, 1);
  256.         if (ptr != NULL) *ptr = '\0';
  257.  
  258.         ctcp_reply(esendnick, data);
  259.     }
  260.     else
  261.     {
  262.         if (esendaddr == NULL)
  263.         {
  264.             /* notice from server */
  265.             chan = channel_joined(eserver, channame);
  266.             drawtext(chan == NULL ? edefwin : chan->window, TXT_TYPE_SERVER_TEXT,
  267.                      "!%s %s\n", esendnick, data);
  268.         }
  269.         else
  270.         {
  271.             /* notice from user */
  272.             if (*channame == '#' || *channame == '&')
  273.             {
  274.                 /* notice in some channel */
  275.                 chan = channel_joined(eserver, channame);
  276.                 drawtext(chan == NULL ? edefwin : chan->window, TXT_TYPE_DEFAULT,
  277.                          "-%3%s%n:%4%s%n- %s\n", esendnick, channame, data);
  278.             }
  279.             else
  280.             {
  281.                 /* private notice */
  282.                 chan = channel_joined(eserver, esendnick);
  283.                 drawtext(chan == NULL ? edefwin : chan->window, TXT_TYPE_DEFAULT,
  284.                          "-%3%s%n(%4%s%n)- %s\n", esendnick, esendaddr, data);
  285.             }
  286.         }
  287.     }
  288. }
  289.  
  290. /* Check if nick is joined to any channel in specified window */
  291. static int nick_joined(WINDOW_REC *win, char *nick)
  292. {
  293.     GList *chan, *nicks;
  294.  
  295.     g_return_val_if_fail(win != NULL, 0);
  296.     g_return_val_if_fail(nick != NULL, 0);
  297.  
  298.     for (chan = g_list_first(win->chanlist); chan != NULL; chan = chan->next)
  299.     {
  300.         for (nicks = g_list_first(((CHAN_REC *) chan->data)->nicks); nicks != NULL; nicks = nicks->next)
  301.         {
  302.             char *tmp;
  303.  
  304.             tmp = (char *) nicks->data;
  305.             if (strcasecmp(isircflag(*tmp) ? tmp+1 : tmp, nick) == 0)
  306.             {
  307.                 return 1;
  308.             }
  309.         }
  310.     }
  311.     return 0;
  312. }
  313.  
  314. void eirc_nick(char *data)
  315. {
  316.     char *nick, *oldnick;
  317.     GList *win;
  318.  
  319.     g_return_if_fail(data != NULL);
  320.  
  321.     nick = event_get_param(&data);
  322.  
  323.     if (strcasecmp(esendnick, eserver->nick) == 0)
  324.     {
  325.         /* You changed your nick */
  326.         oldnick = eserver->nick;
  327.         eserver->nick = g_strdup(nick);
  328.         gui_nick_change(eserver, oldnick, nick);
  329.         g_free(oldnick);
  330.         drawtext(edefwin, TXT_TYPE_SERVER_TEXT, IRCTXT_YOUR_NICK_CHANGED, eserver->nick);
  331.         gui_update_statusbar(NULL);
  332.     }
  333.     else
  334.     {
  335.         /* Someone else changed nick */
  336.         for (win = g_list_first(winlist); win != NULL; win = win->next)
  337.         {
  338.             WINDOW_REC *winrec;
  339.  
  340.             winrec = (WINDOW_REC *) win->data;
  341.             if (nick_joined((WINDOW_REC *) win->data, esendnick))
  342.                 drawtext(winrec, TXT_TYPE_SERVER_TEXT, IRCTXT_NICK_CHANGED, esendnick, nick);
  343.         }
  344.         gui_nick_change(eserver, esendnick, nick);
  345.     }
  346.  
  347.     for (win = g_list_first(winlist); win != NULL; win = win->next)
  348.     {
  349.         WINDOW_REC *winrec;
  350.         GList *chan;
  351.  
  352.         winrec = (WINDOW_REC *) win->data;
  353.         for (chan = g_list_first(winrec->chanlist); chan != NULL; chan = chan->next)
  354.             change_nick((CHAN_REC *) chan->data, esendnick, nick);
  355.     }
  356. }
  357.  
  358. void eirc_join(char *data)
  359. {
  360.     char *channame;
  361.     CHAN_REC *chan;
  362.  
  363.     g_return_if_fail(data != NULL);
  364.  
  365.     channame = event_get_param(&data);
  366.     chan = channel_joined(eserver, channame);
  367.  
  368.     drawtext(chan == NULL ? edefwin : chan->window, TXT_TYPE_SERVER_TEXT,
  369.              IRCTXT_JOIN, esendnick, esendaddr, channame);
  370.  
  371.     if (chan != NULL && strcasecmp(esendnick, eserver->nick) != 0)
  372.     {
  373.         /* someone else joined channel */
  374.         chan->nicks = g_list_insert_sorted(chan->nicks, g_strdup(esendnick), (GCompareFunc) irc_nicks_compare);
  375.         gui_channel_join(chan, esendnick);
  376.     }
  377. }
  378.  
  379. void eirc_part(char *data)
  380. {
  381.     char *channame, *reason;
  382.     CHAN_REC *chan;
  383.     WINDOW_REC *win;
  384.  
  385.     g_return_if_fail(data != NULL);
  386.  
  387.     event_get_params(data, 2, &channame, &reason);
  388.     chan = channel_joined(eserver, channame);
  389.  
  390.     drawtext(chan == NULL ? edefwin : chan->window, TXT_TYPE_SERVER_TEXT, IRCTXT_PART,
  391.              esendnick, esendaddr, channame, reason);
  392.     if (chan == NULL) return;
  393.  
  394.     if (strcasecmp(esendnick, eserver->nick) != 0)
  395.     {
  396.         /* someone else left channel */
  397.         remove_nick(chan, esendnick);
  398.         gui_channel_part(chan, esendnick);
  399.         return;
  400.     }
  401.  
  402.     win = chan->window;
  403.     if (chan == win->curchan)
  404.         irc_select_new_channel(chan->window);
  405.  
  406.     gui_channel_part(chan, NULL);
  407.     irc_chan_free(chan);
  408.     if (win->chanlist == NULL && /* no channels left in this window */
  409.         g_list_first(winlist)->next != NULL) /* this isn't the last window */
  410.     {
  411.         /* so close the window.. */
  412.         irc_window_close(win);
  413.     }
  414. }
  415.  
  416. void eirc_ping(char *data)
  417. {
  418.     int conn;
  419.     char *tmp;
  420.  
  421.     g_return_if_fail(data != NULL);
  422.  
  423.     /* irc_send_cmd() doesn't send commands until server has sent connection
  424.        messages but PING can be sent before connection has happened, so fake
  425.        connection */
  426.  
  427.     tmp = (char *) g_malloc(strlen(data)+6);
  428.     conn = eserver->connected;
  429.     eserver->connected = 1;
  430.     sprintf(tmp, "PONG %s", data);
  431.     irc_send_cmd(eserver, tmp);
  432.     eserver->connected = conn;
  433.     g_free(tmp);
  434. }
  435.  
  436. void eirc_pong(char *data)
  437. {
  438.     char *host, *reply;
  439.     g_return_if_fail(data != NULL);
  440.  
  441.     event_get_params(data, 2, &host, &reply);
  442.  
  443.     drawtext(edefwin, TXT_TYPE_SERVER_TEXT, IRCTXT_PONG, host, reply);
  444. }
  445.  
  446. void eirc_quit(char *data)
  447. {
  448.     GList *win;
  449.  
  450.     g_return_if_fail(data != NULL);
  451.  
  452.     if (*data == ':') data++; /* quit message */
  453.     for (win = g_list_first(winlist); win != NULL; win = win->next)
  454.     {
  455.         WINDOW_REC *winrec;
  456.         GList *chan;
  457.  
  458.         winrec = (WINDOW_REC *) win->data;
  459.         if (nick_joined(winrec, esendnick))
  460.             drawtext(winrec, TXT_TYPE_SERVER_TEXT, IRCTXT_QUIT, esendnick, esendaddr, data);
  461.  
  462.         for (chan = g_list_first(winrec->chanlist); chan != NULL; chan = chan->next)
  463.             remove_nick((CHAN_REC *) chan->data, esendnick);
  464.     }
  465.  
  466.     gui_channel_part(NULL, esendnick);
  467. }
  468.  
  469. void eirc_mode(char *data)
  470. {
  471.     char *ptr, *mode, *channame, type;
  472.     CHAN_REC *chan;
  473.  
  474.     g_return_if_fail(data != NULL);
  475.  
  476.     channame = event_get_param(&data);
  477.     if (*data == ':') data++;
  478.  
  479.     if (*channame == '#' || *channame == '&')
  480.     {
  481.         /* channel mode change */
  482.         chan = channel_joined(eserver, channame);
  483.         drawtext(chan == NULL ? edefwin : chan->window, TXT_TYPE_SERVER_TEXT,
  484.                  IRCTXT_CHANMODE_CHANGE, channame, data, esendnick);
  485.         if (chan == NULL) return;
  486.     }
  487.     else
  488.     {
  489.         /* user mode change */
  490.         drawtext(edefwin, TXT_TYPE_SERVER_TEXT, IRCTXT_USERMODE_CHANGE, data, channame);
  491.         return;
  492.     }
  493.  
  494.     type = '+';
  495.     for (mode = event_get_param(&data); *mode != '\0'; mode++)
  496.     {
  497.         if (*mode == '+' || *mode == '-')
  498.         {
  499.             type = *mode;
  500.             continue;
  501.         }
  502.  
  503.         switch (*mode)
  504.         {
  505.             case 'v':
  506.                 ptr = event_get_param(&data);
  507.                 if (*ptr != '\0')
  508.                 {
  509.                     gui_change_nick_mode(chan, ptr, type == '+' ? '+' : ' ');
  510.                     nick_mode_change(chan, ptr, type == '+' ? '+' : ' ');
  511.                 }
  512.                 break;
  513.  
  514.             case 'o':
  515.                 ptr = event_get_param(&data);
  516.                 if (*ptr != '\0')
  517.                 {
  518.                     gui_change_nick_mode(chan, ptr, type == '+' ? '@' : ' ');
  519.                     nick_mode_change(chan, ptr, type == '+' ? '@' : ' ');
  520.                 }
  521.                 break;
  522.  
  523.             case 'l':
  524.             case 'k':
  525.                 ptr = event_get_param(&data);
  526.                 break;
  527.         }
  528.     }
  529. }
  530.  
  531.  
  532. void eirc_kick(char *data)
  533. {
  534.     CHAN_REC *chan;
  535.     char *channame, *nick, *reason;
  536.  
  537.     g_return_if_fail(data != NULL);
  538.  
  539.     event_get_params(data, 3, &channame, &nick, &reason);
  540.     chan = channel_joined(eserver, channame);
  541.  
  542.     drawtext(chan == NULL ? edefwin : chan->window, TXT_TYPE_SERVER_TEXT, IRCTXT_KICK,
  543.              nick, channame, esendnick, reason);
  544.     if (chan == NULL) return;
  545.  
  546.     if (strcasecmp(nick, eserver->nick) != 0)
  547.     {
  548.         /* someone else was kicked */
  549.         remove_nick(chan, nick);
  550.         gui_channel_part(chan, nick);
  551.         return;
  552.     }
  553.  
  554.     if (chan == chan->window->curchan)
  555.         irc_select_new_channel(chan->window);
  556.  
  557.     gui_channel_part(chan, NULL);
  558. }
  559.  
  560. void eirc_invite(char *data)
  561. {
  562.     char *chan;
  563.  
  564.     g_return_if_fail(data != NULL);
  565.  
  566.     event_get_params(data, 2, NULL, &chan);
  567.     if (*chan != '\0')
  568.         drawtext(curwin, TXT_TYPE_SERVER_TEXT, IRCTXT_INVITE, esendnick, chan);
  569. }
  570.  
  571. void eirc_new_topic(char *data)
  572. {
  573.     CHAN_REC *chan;
  574.     char *channame, *topic;
  575.  
  576.     g_return_if_fail(data != NULL);
  577.  
  578.     event_get_params(data, 2, &channame, &topic);
  579.     chan = channel_joined(eserver, channame);
  580.     if (chan == NULL) return;
  581.  
  582.     if (chan->topic != NULL) g_free(chan->topic);
  583.     chan->topic = *topic == '\0' ? NULL : g_strdup(topic);
  584.  
  585.     if (chan->topic != NULL)
  586.         drawtext(chan->window, TXT_TYPE_SERVER_TEXT, IRCTXT_NEW_TOPIC,
  587.                  esendnick, chan->name, chan->topic);
  588.  
  589.     gui_change_topic(chan);
  590. }
  591.  
  592. void eirc_error(char *data)
  593. {
  594.     g_return_if_fail(data != NULL);
  595.  
  596.     if (*data == ':') data++;
  597.     drawtext(curwin, TXT_TYPE_SERVER_TEXT, IRCTXT_ERROR, data);
  598. }
  599.