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 >
Wrap
C/C++ Source or Header
|
1998-05-09
|
17KB
|
599 lines
/*
events-named.c : Functions to handle (named) IRC server replies
Copyright (C) 1998 Timo Sirainen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <glib.h>
#include "os.h"
#include "irc.h"
#include "txt.h"
#include "gui.h"
#include "ctcp.h"
#include "events.h"
char *esendnick, *esendaddr;
SERVER_REC *eserver;
WINDOW_REC *edefwin;
typedef int (*CALL_FUNC)(char *, char *, char *);
struct CMD_STRUCT
{
char *name;
CALL_FUNC func;
} CMD_STRUCT;
static struct CMD_STRUCT ctcp_cmds[] =
{
{ "VERSION", (CALL_FUNC) ctcp_version },
{ "PING", (CALL_FUNC) ctcp_ping },
{ "ACTION", (CALL_FUNC) ctcp_action },
{ "DCC", (CALL_FUNC) ctcp_dcc },
{ NULL, NULL }
};
/* Remove nick from list */
static void remove_nick(CHAN_REC *chan, char *nick)
{
char *data;
GList *tmp;
g_return_if_fail(chan != NULL);
g_return_if_fail(nick != NULL);
tmp = g_list_first(chan->nicks);
while (tmp != NULL)
{
data = (char *) tmp->data;
if (strcasecmp(isircflag(*data) ? data+1 : data, nick) == 0)
{
g_free(tmp->data);
chan->nicks = g_list_remove_link(chan->nicks, tmp);
break;
}
tmp = tmp->next;
}
}
/* Change nick mode in list */
static void nick_mode_change(CHAN_REC *chan, char *nick, char mode)
{
char *data;
GList *tmp;
g_return_if_fail(chan != NULL);
g_return_if_fail(nick != NULL);
tmp = g_list_first(chan->nicks);
while (tmp != NULL)
{
data = (char *) tmp->data;
if (strcasecmp(isircflag(*data) ? data+1 : data, nick) == 0)
{
/* remove old nick from list */
g_free(tmp->data);
chan->nicks = g_list_remove_link(chan->nicks, tmp);
/* insert new nick to list */
data = g_malloc(strlen(nick)+1);
if (mode != ' ')
sprintf(data, "%c%s", mode, nick);
else
strcpy(data, nick);
chan->nicks = g_list_insert_sorted(chan->nicks, data, (GCompareFunc) irc_nicks_compare);
break;
}
tmp = tmp->next;
}
}
/* Change nick name in list */
static void change_nick(CHAN_REC *chan, char *oldnick, char *newnick)
{
char *data, mode;
GList *tmp;
g_return_if_fail(chan != NULL);
g_return_if_fail(oldnick != NULL);
g_return_if_fail(newnick != NULL);
tmp = g_list_first(chan->nicks);
while (tmp != NULL)
{
data = (char *) tmp->data;
if (strcasecmp(isircflag(*data) ? data+1 : data, oldnick) == 0)
{
mode = isircflag(*data) ? *data : ' ';
/* remove old nick from list */
g_free(tmp->data);
chan->nicks = g_list_remove_link(chan->nicks, tmp);
/* insert new nick to list */
data = g_malloc(strlen(newnick)+1);
if (mode != ' ')
sprintf(data, "%c%s", mode, newnick);
else
strcpy(data, newnick);
chan->nicks = g_list_insert_sorted(chan->nicks, data, (GCompareFunc) irc_nicks_compare);
break;
}
tmp = tmp->next;
}
}
void eirc_privmsg(char *data)
{
char *channame;
CHAN_REC *chan;
g_return_if_fail(data != NULL);
channame = event_get_param(&data); /* Channel or nick name */
if (*data == ':') data++;
if (esendnick == NULL) esendnick = "!server!";
if (*data == 1)
{
/* ctcp message */
char *ptr;
int n, ret;
if (irc_is_ignored(esendnick, IGNORE_CTCP)) return;
/* remove the later \001 */
ptr = strchr(++data, 1);
if (ptr != NULL)
*ptr = *(ptr+1) == '\0' ? '\0' : ' ';
/* skip "CTCP" */
for (ptr = data; *ptr != ' ' && *ptr != '\0'; ptr++) ;
if (*ptr == ' ') *ptr++ = '\0';
ret = 2;
for (n = 0; ctcp_cmds[n].name != NULL; n++)
{
if (strcasecmp(ctcp_cmds[n].name, data) == 0)
{
ret = ctcp_cmds[n].func(esendnick, channame, ptr);
break;
}
}
if (ret)
{
drawtext(edefwin, TXT_TYPE_DEFAULT, "%9>>> %_%s%_ requested %s%!%_%s%_%! from %_%s\n", esendnick,
ret == 1 ? "" : "unknown ctcp ", data, channame);
}
return;
}
if (channame[0] == '#' || channame[0] == '&')
{
/* message to some channel */
char *nick;
int nicklen;
WINDOW_REC *win;
if (irc_is_ignored(esendnick, IGNORE_PUBLIC)) return;
chan = channel_joined(eserver, channame);
nick = chan != NULL ? chan->server->nick : eserver->nick;
nicklen = strlen(nick);
win = chan == NULL ? edefwin : chan->window;
if (strncasecmp(data, nick, nicklen) == 0 && !isalnum(data[nicklen]))
{
/* found your nick at the start of the line */
if (chan != NULL && strcasecmp(channame, chan->window->curchan->name) == 0)
drawtext(win, TXT_TYPE_DEFAULT, "<%1%s%n> %s\n", esendnick, data); /* message sent in this channel */
else
drawtext(win, TXT_TYPE_DEFAULT, "<%1%s%n:%2%s%n> %s\n", esendnick, channame, data); /* message sent to some other channel */
}
else
{
if (chan != NULL && strcasecmp(channame, chan->window->curchan->name) == 0)
drawtext(win, TXT_TYPE_DEFAULT, "<%s> %s\n", esendnick, data); /* message sent in this channel */
else
drawtext(win, TXT_TYPE_DEFAULT, "<%s:%2%s%n> %s\n", esendnick, channame, data); /* message sent to some other channel */
}
}
else
{
/* private message */
if (irc_is_ignored(esendnick, IGNORE_PRIVATE)) return;
chan = channel_joined(eserver, esendnick);
drawtext(chan == NULL ? edefwin : chan->window, TXT_TYPE_DEFAULT,
"[%3%s%n(%4%s%n)]%n %s\n",
esendnick, esendaddr == NULL ? "" : esendaddr, data);
}
if (chan != NULL && !chan->new_data && chan->window != curwin)
{
chan->new_data = 1;
gui_channel_hilight(chan);
}
}
void eirc_notice(char *data)
{
char *channame;
CHAN_REC *chan;
g_return_if_fail(data != NULL);
channame = event_get_param(&data); /* Channel or nick name */
if (*data == ':') data++; /* notice text */
if (esendnick == NULL) esendnick = "server";
if (*data == 1)
{
/* ctcp reply */
char *ptr;
ptr = strchr(++data, 1);
if (ptr != NULL) *ptr = '\0';
ctcp_reply(esendnick, data);
}
else
{
if (esendaddr == NULL)
{
/* notice from server */
chan = channel_joined(eserver, channame);
drawtext(chan == NULL ? edefwin : chan->window, TXT_TYPE_SERVER_TEXT,
"!%s %s\n", esendnick, data);
}
else
{
/* notice from user */
if (*channame == '#' || *channame == '&')
{
/* notice in some channel */
chan = channel_joined(eserver, channame);
drawtext(chan == NULL ? edefwin : chan->window, TXT_TYPE_DEFAULT,
"-%3%s%n:%4%s%n- %s\n", esendnick, channame, data);
}
else
{
/* private notice */
chan = channel_joined(eserver, esendnick);
drawtext(chan == NULL ? edefwin : chan->window, TXT_TYPE_DEFAULT,
"-%3%s%n(%4%s%n)- %s\n", esendnick, esendaddr, data);
}
}
}
}
/* Check if nick is joined to any channel in specified window */
static int nick_joined(WINDOW_REC *win, char *nick)
{
GList *chan, *nicks;
g_return_val_if_fail(win != NULL, 0);
g_return_val_if_fail(nick != NULL, 0);
for (chan = g_list_first(win->chanlist); chan != NULL; chan = chan->next)
{
for (nicks = g_list_first(((CHAN_REC *) chan->data)->nicks); nicks != NULL; nicks = nicks->next)
{
char *tmp;
tmp = (char *) nicks->data;
if (strcasecmp(isircflag(*tmp) ? tmp+1 : tmp, nick) == 0)
{
return 1;
}
}
}
return 0;
}
void eirc_nick(char *data)
{
char *nick, *oldnick;
GList *win;
g_return_if_fail(data != NULL);
nick = event_get_param(&data);
if (strcasecmp(esendnick, eserver->nick) == 0)
{
/* You changed your nick */
oldnick = eserver->nick;
eserver->nick = g_strdup(nick);
gui_nick_change(eserver, oldnick, nick);
g_free(oldnick);
drawtext(edefwin, TXT_TYPE_SERVER_TEXT, IRCTXT_YOUR_NICK_CHANGED, eserver->nick);
gui_update_statusbar(NULL);
}
else
{
/* Someone else changed nick */
for (win = g_list_first(winlist); win != NULL; win = win->next)
{
WINDOW_REC *winrec;
winrec = (WINDOW_REC *) win->data;
if (nick_joined((WINDOW_REC *) win->data, esendnick))
drawtext(winrec, TXT_TYPE_SERVER_TEXT, IRCTXT_NICK_CHANGED, esendnick, nick);
}
gui_nick_change(eserver, esendnick, nick);
}
for (win = g_list_first(winlist); win != NULL; win = win->next)
{
WINDOW_REC *winrec;
GList *chan;
winrec = (WINDOW_REC *) win->data;
for (chan = g_list_first(winrec->chanlist); chan != NULL; chan = chan->next)
change_nick((CHAN_REC *) chan->data, esendnick, nick);
}
}
void eirc_join(char *data)
{
char *channame;
CHAN_REC *chan;
g_return_if_fail(data != NULL);
channame = event_get_param(&data);
chan = channel_joined(eserver, channame);
drawtext(chan == NULL ? edefwin : chan->window, TXT_TYPE_SERVER_TEXT,
IRCTXT_JOIN, esendnick, esendaddr, channame);
if (chan != NULL && strcasecmp(esendnick, eserver->nick) != 0)
{
/* someone else joined channel */
chan->nicks = g_list_insert_sorted(chan->nicks, g_strdup(esendnick), (GCompareFunc) irc_nicks_compare);
gui_channel_join(chan, esendnick);
}
}
void eirc_part(char *data)
{
char *channame, *reason;
CHAN_REC *chan;
WINDOW_REC *win;
g_return_if_fail(data != NULL);
event_get_params(data, 2, &channame, &reason);
chan = channel_joined(eserver, channame);
drawtext(chan == NULL ? edefwin : chan->window, TXT_TYPE_SERVER_TEXT, IRCTXT_PART,
esendnick, esendaddr, channame, reason);
if (chan == NULL) return;
if (strcasecmp(esendnick, eserver->nick) != 0)
{
/* someone else left channel */
remove_nick(chan, esendnick);
gui_channel_part(chan, esendnick);
return;
}
win = chan->window;
if (chan == win->curchan)
irc_select_new_channel(chan->window);
gui_channel_part(chan, NULL);
irc_chan_free(chan);
if (win->chanlist == NULL && /* no channels left in this window */
g_list_first(winlist)->next != NULL) /* this isn't the last window */
{
/* so close the window.. */
irc_window_close(win);
}
}
void eirc_ping(char *data)
{
int conn;
char *tmp;
g_return_if_fail(data != NULL);
/* irc_send_cmd() doesn't send commands until server has sent connection
messages but PING can be sent before connection has happened, so fake
connection */
tmp = (char *) g_malloc(strlen(data)+6);
conn = eserver->connected;
eserver->connected = 1;
sprintf(tmp, "PONG %s", data);
irc_send_cmd(eserver, tmp);
eserver->connected = conn;
g_free(tmp);
}
void eirc_pong(char *data)
{
char *host, *reply;
g_return_if_fail(data != NULL);
event_get_params(data, 2, &host, &reply);
drawtext(edefwin, TXT_TYPE_SERVER_TEXT, IRCTXT_PONG, host, reply);
}
void eirc_quit(char *data)
{
GList *win;
g_return_if_fail(data != NULL);
if (*data == ':') data++; /* quit message */
for (win = g_list_first(winlist); win != NULL; win = win->next)
{
WINDOW_REC *winrec;
GList *chan;
winrec = (WINDOW_REC *) win->data;
if (nick_joined(winrec, esendnick))
drawtext(winrec, TXT_TYPE_SERVER_TEXT, IRCTXT_QUIT, esendnick, esendaddr, data);
for (chan = g_list_first(winrec->chanlist); chan != NULL; chan = chan->next)
remove_nick((CHAN_REC *) chan->data, esendnick);
}
gui_channel_part(NULL, esendnick);
}
void eirc_mode(char *data)
{
char *ptr, *mode, *channame, type;
CHAN_REC *chan;
g_return_if_fail(data != NULL);
channame = event_get_param(&data);
if (*data == ':') data++;
if (*channame == '#' || *channame == '&')
{
/* channel mode change */
chan = channel_joined(eserver, channame);
drawtext(chan == NULL ? edefwin : chan->window, TXT_TYPE_SERVER_TEXT,
IRCTXT_CHANMODE_CHANGE, channame, data, esendnick);
if (chan == NULL) return;
}
else
{
/* user mode change */
drawtext(edefwin, TXT_TYPE_SERVER_TEXT, IRCTXT_USERMODE_CHANGE, data, channame);
return;
}
type = '+';
for (mode = event_get_param(&data); *mode != '\0'; mode++)
{
if (*mode == '+' || *mode == '-')
{
type = *mode;
continue;
}
switch (*mode)
{
case 'v':
ptr = event_get_param(&data);
if (*ptr != '\0')
{
gui_change_nick_mode(chan, ptr, type == '+' ? '+' : ' ');
nick_mode_change(chan, ptr, type == '+' ? '+' : ' ');
}
break;
case 'o':
ptr = event_get_param(&data);
if (*ptr != '\0')
{
gui_change_nick_mode(chan, ptr, type == '+' ? '@' : ' ');
nick_mode_change(chan, ptr, type == '+' ? '@' : ' ');
}
break;
case 'l':
case 'k':
ptr = event_get_param(&data);
break;
}
}
}
void eirc_kick(char *data)
{
CHAN_REC *chan;
char *channame, *nick, *reason;
g_return_if_fail(data != NULL);
event_get_params(data, 3, &channame, &nick, &reason);
chan = channel_joined(eserver, channame);
drawtext(chan == NULL ? edefwin : chan->window, TXT_TYPE_SERVER_TEXT, IRCTXT_KICK,
nick, channame, esendnick, reason);
if (chan == NULL) return;
if (strcasecmp(nick, eserver->nick) != 0)
{
/* someone else was kicked */
remove_nick(chan, nick);
gui_channel_part(chan, nick);
return;
}
if (chan == chan->window->curchan)
irc_select_new_channel(chan->window);
gui_channel_part(chan, NULL);
}
void eirc_invite(char *data)
{
char *chan;
g_return_if_fail(data != NULL);
event_get_params(data, 2, NULL, &chan);
if (*chan != '\0')
drawtext(curwin, TXT_TYPE_SERVER_TEXT, IRCTXT_INVITE, esendnick, chan);
}
void eirc_new_topic(char *data)
{
CHAN_REC *chan;
char *channame, *topic;
g_return_if_fail(data != NULL);
event_get_params(data, 2, &channame, &topic);
chan = channel_joined(eserver, channame);
if (chan == NULL) return;
if (chan->topic != NULL) g_free(chan->topic);
chan->topic = *topic == '\0' ? NULL : g_strdup(topic);
if (chan->topic != NULL)
drawtext(chan->window, TXT_TYPE_SERVER_TEXT, IRCTXT_NEW_TOPIC,
esendnick, chan->name, chan->topic);
gui_change_topic(chan);
}
void eirc_error(char *data)
{
g_return_if_fail(data != NULL);
if (*data == ':') data++;
drawtext(curwin, TXT_TYPE_SERVER_TEXT, IRCTXT_ERROR, data);
}