?? irc-proto.c
字號:
/* * irc-proto.c - basic IRC protocol functions * * Copyright (C) 2000, 2001 Stefan Jahn <stefan@lkcc.org> * * This 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, or (at your option) * any later version. * * This software 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 package; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * $Id: irc-proto.c,v 1.35 2001/07/06 16:40:02 ela Exp $ * */#if HAVE_CONFIG_H# include <config.h>#endif#if ENABLE_IRC_PROTO#define _GNU_SOURCE#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#if HAVE_STRINGS_H# include <strings.h>#endif#ifdef __MINGW32__# include <winsock2.h>#endif#ifndef __MINGW32__# include <sys/types.h># include <netinet/in.h>#endif#include "libserveez.h"#include "irc-core/irc-core.h"#include "irc-proto.h"#include "irc-event.h"#include "irc-server.h"#include "irc-config.h"/* * The IRC server instance default configuration, */irc_config_t irc_config ={ 0, /* logged in operators */ 0, /* logged in users */ 0, /* unknown connections */ 0, /* invisible users */ NULL, /* virtual host name */ NULL, /* read server host name */ 42424, /* listening tcp port */ 0, /* is USERS command disable ? */#if ENABLE_TIMESTAMP 0, /* delta value to UTC */#endif { NULL }, /* message of the day */ 0, /* message of the day lines */ 0, /* motd last modified date */ "../data/irc-MOTD.txt", /* file name of message of the day */ NULL, /* MLine */ NULL, /* ALine */ NULL, /* YLines */ NULL, /* ILines */ NULL, /* OLines */ NULL, /* oLines */ NULL, /* CLines */ NULL, /* NLines */ NULL, /* KLines */ NULL, /* server password */ NULL, /* server info */ NULL, /* email address of maintainers */ NULL, /* admininfo */ NULL, /* location1 */ NULL, /* location2 */ NULL, /* irc channel hash */ NULL, /* irc client hash */ NULL, /* irc server list root */ NULL, /* client history list root */ NULL, /* connection classes list */ NULL, /* user authorizations */ NULL, /* operator authorizations */ NULL, /* banned users */ NULL /* name of the /INFO file */};/* * Definition of the configuration items. */svz_key_value_pair_t irc_config_prototype[] ={ SVZ_REGISTER_STR ("MOTD-file", irc_config.MOTD_file, SVZ_ITEM_DEFAULTABLE), SVZ_REGISTER_STR ("INFO-file", irc_config.info_file, SVZ_ITEM_DEFAULTABLE),#if ENABLE_TIMESTAMP SVZ_REGISTER_INT ("tsdelta", irc_config.tsdelta, SVZ_ITEM_DEFAULTABLE),#endif SVZ_REGISTER_STR ("admininfo", irc_config.admininfo, SVZ_ITEM_NOTDEFAULTABLE), SVZ_REGISTER_STR ("M-line", irc_config.MLine, SVZ_ITEM_NOTDEFAULTABLE), SVZ_REGISTER_STR ("A-line", irc_config.ALine, SVZ_ITEM_DEFAULTABLE), SVZ_REGISTER_STRARRAY ("Y-lines", irc_config.YLine, SVZ_ITEM_DEFAULTABLE), SVZ_REGISTER_STRARRAY ("I-lines", irc_config.ILine, SVZ_ITEM_DEFAULTABLE), SVZ_REGISTER_STRARRAY ("O-lines", irc_config.OLine, SVZ_ITEM_DEFAULTABLE), SVZ_REGISTER_STRARRAY ("o-lines", irc_config.oLine, SVZ_ITEM_DEFAULTABLE), SVZ_REGISTER_STRARRAY ("C-lines", irc_config.CLine, SVZ_ITEM_DEFAULTABLE), SVZ_REGISTER_STRARRAY ("N-lines", irc_config.NLine, SVZ_ITEM_DEFAULTABLE), SVZ_REGISTER_STRARRAY ("K-lines", irc_config.KLine, SVZ_ITEM_DEFAULTABLE), SVZ_REGISTER_END ()};/* * Definition of the IRC server. */svz_servertype_t irc_server_definition ={ "irc server", /* long description */ "irc", /* short description for instantiating */ irc_global_init, /* global initializer */ irc_init, /* instance initializer */ irc_detect_proto, /* detection routine */ irc_connect_socket, /* connection routine */ irc_finalize, /* instance finalizer */ irc_global_finalize, /* global finalizer */ NULL, /* client info */ NULL, /* server info */ NULL, /* server timer */ NULL, /* handle request callback */ &irc_config, /* default configuration */ sizeof (irc_config), /* size of configuration */ irc_config_prototype /* configuration prototypes */};/* Static forward declarations. */static int irc_delete_channel (irc_config_t *cfg, irc_channel_t *);static irc_channel_t *irc_add_channel (irc_config_t *cfg, char *channel);/* * Global IRC server initializer. */intirc_global_init (svz_servertype_t *server){#if 0 printf ("sizeof (socket_t) = %d\n", sizeof (socket_data_t)); printf ("sizeof (irc_ban_t) = %d\n", sizeof (irc_ban_t)); printf ("sizeof (irc_channel_t) = %d\n", sizeof (irc_channel_t)); printf ("sizeof (irc_client_t) = %d\n", sizeof (irc_client_t)); printf ("sizeof (irc_client_history_t) = %d\n", sizeof (irc_client_history_t)); printf ("sizeof (irc_server_t) = %d\n", sizeof (irc_server_t)); printf ("sizeof (irc_user_t) = %d\n", sizeof (irc_user_t)); printf ("sizeof (irc_kill_t) = %d\n", sizeof (irc_kill_t)); printf ("sizeof (irc_oper_t) = %d\n", sizeof (irc_oper_t)); printf ("sizeof (irc_class_t) = %d\n", sizeof (irc_class_t));#endif irc_create_lcset (); return 0;}/* * Global IRC server finalizer. */intirc_global_finalize (svz_servertype_t *server){ return 0;}/* * Initialization of the IRC server instance. */intirc_init (svz_server_t *server){ irc_config_t *cfg = server->cfg; char tmp[3][256]; /* scan the M line (server configuration) */ if (!cfg->MLine || irc_parse_line (cfg->MLine, "M:%s:%s:%s:%d", tmp[0], tmp[1], tmp[2], &cfg->port) != 4) { svz_log (LOG_ERROR, "irc: invalid M line: %s\n", cfg->MLine ? cfg->MLine : "(nil)"); return -1; } /* FIXME: ??? if (cfg->port != cfg->netport->port) { svz_log (LOG_WARNING, "irc: port in M line clashes\n"); cfg->netport->port = (short) cfg->port; } */ cfg->host = svz_strdup (tmp[0]); cfg->realhost = svz_strdup (tmp[1]); cfg->info = svz_strdup (tmp[2]); /* scan the A line (administrative information) */ if (!cfg->ALine || irc_parse_line (cfg->ALine, "A:%s:%s:%s", tmp[0], tmp[1], tmp[2]) != 3) { svz_log (LOG_ERROR, "irc: invalid A line: %s\n", cfg->ALine ? cfg->ALine : "(nil)"); return -1; } cfg->location1 = svz_strdup (tmp[0]); cfg->location2 = svz_strdup (tmp[1]); cfg->email = svz_strdup (tmp[2]); /* initialize hashes and lists */ cfg->clients = svz_hash_create (4); cfg->channels = svz_hash_create (4); cfg->clients->equals = irc_string_equal; cfg->channels->equals = irc_string_equal; cfg->servers = NULL; cfg->history = NULL; irc_parse_config_lines (cfg); irc_connect_servers (cfg); return 0;}/* * IRC server instance finalizer. */intirc_finalize (svz_server_t *server){ irc_config_t *cfg = server->cfg; int n; /* free the MOTD */ for (n = 0; n < cfg->MOTDs; n++) svz_free (cfg->MOTD[n]); /* free configuration hash variables */ svz_free (cfg->host); svz_free (cfg->info); svz_free (cfg->realhost); svz_free (cfg->location1); svz_free (cfg->location2); svz_free (cfg->email); irc_free_config_lines (cfg); /* free the client history */ irc_delete_client_history (cfg); /* free the server IRC list */ irc_delete_servers (cfg); svz_hash_destroy (cfg->clients); svz_hash_destroy (cfg->channels); return 0;}/* * Check if a certain client is in a channel. Return -1 if not and * return the client's position in the channel list. This is useful to * to detect its channel flags. If you passed a valid socket the * ERR_NOTONCHANNEL reply is sent to the socket. */intirc_client_in_channel (svz_socket_t *sock, /* client's socket */ irc_client_t *client, /* the client structure */ irc_channel_t *channel) /* the channel to search */{ irc_config_t *cfg; int n; /* find client in the channel, return position if found */ for (n = 0; n < channel->clients; n++) if (channel->client[n] == client) return n; /* not in channel ! */ if (sock) { cfg = sock->cfg; irc_printf (sock, ":%s %03d %s " ERR_NOTONCHANNEL_TEXT "\n", cfg->host, ERR_NOTONCHANNEL, client->nick, channel->name); } return -1;}/* * Add a nick to a certain channel. */intirc_join_channel (irc_config_t *cfg, irc_client_t *client, char *chan){ irc_channel_t *channel; int n; /* does the channel exist locally ? */ if ((channel = irc_find_channel (cfg, chan)) != NULL) { /* is the nick already in the channel ? */ for (n = 0; n < channel->clients; n++) if (channel->client[n] == client) break; /* no, add nick to channel */ if (n == channel->clients) { /* joined just too many channels ? */ if (client->channels >= MAX_CHANNELS) { irc_printf (client->sock, ":%s %03d %s " ERR_TOOMANYCHANNELS_TEXT "\n", cfg->host, ERR_TOOMANYCHANNELS, client->nick, channel->name); } else { channel->client = svz_realloc (channel->client, sizeof (irc_client_t *) * (n + 1)); channel->cflag = svz_realloc (channel->cflag, sizeof (int) * (n + 1)); channel->client[n] = client; channel->cflag[n] = 0; channel->clients++;#if ENABLE_DEBUG svz_log (LOG_DEBUG, "irc: %s joined channel %s\n", client->nick, channel->name);#endif n = client->channels; client->channel = svz_realloc (client->channel, sizeof (irc_channel_t *) * (n + 1)); client->channel[n] = channel; client->channels++; } } } /* no, the channel does not exists, yet */ else { /* check if the client has not joined too many channels */ if (client->channels >= MAX_CHANNELS) { irc_printf (client->sock, ":%s %03d %s " ERR_TOOMANYCHANNELS_TEXT "\n", cfg->host, ERR_TOOMANYCHANNELS, client->nick, chan); return 0; } /* create one and set the first client as operator */ channel = irc_add_channel (cfg, chan); channel->client = svz_malloc (sizeof (irc_client_t *)); channel->cflag = svz_malloc (sizeof (int)); channel->client[0] = client; channel->cflag[0] = MODE_OPERATOR; channel->clients = 1; channel->by = svz_strdup (client->nick); channel->since = time (NULL);#if ENABLE_DEBUG svz_log (LOG_DEBUG, "irc: channel %s created\n", channel->name); svz_log (LOG_DEBUG, "irc: %s joined channel %s\n", client->nick, channel->name);#endif n = client->channels; client->channel = svz_realloc (client->channel, sizeof (irc_channel_t *) * (n + 1)); client->channel[n] = channel; client->channels++; } return 0;}/* * Delete a client of a given channel. */intirc_leave_channel (irc_config_t *cfg, irc_client_t *client, irc_channel_t *channel){ int n, i, last; /* delete the client of this channel */ last = channel->clients - 1; for (n = 0; n < channel->clients; n++) if (channel->client[n] == client) { channel->clients--; if (last) { channel->client[n] = channel->client[last]; channel->cflag[n] = channel->cflag[last]; channel->client = svz_realloc (channel->client, sizeof (irc_client_t *) * last); channel->cflag = svz_realloc (channel->cflag, sizeof (int) * last); } else { svz_free (channel->client); channel->client = NULL; svz_free (channel->cflag); channel->cflag = NULL; }#if ENABLE_DEBUG svz_log (LOG_DEBUG, "irc: %s left channel %s\n", client->nick, channel->name);#endif /* clear this channel of client's list */ last = client->channels - 1; for (i = 0; i < client->channels; i++) if (client->channel[i] == channel) { if (--client->channels != 0) { client->channel[i] = client->channel[last]; client->channel = svz_realloc (client->channel, sizeof (irc_channel_t *) * client->channels); } else { svz_free (client->channel); client->channel = NULL; } break; } break; } /* no client in channel ? */ if (channel->clients == 0) {#if ENABLE_DEBUG svz_log (LOG_DEBUG, "irc: channel %s destroyed\n", channel->name);#endif irc_delete_channel (cfg, channel); } return 0;}/* * Send an error message if there are not enough arguments given. * Return non zero if there are less than necessary. */intirc_check_args (svz_socket_t *sock, /* the client's socket */ irc_client_t *client, /* the irc client itself */ irc_config_t *conf, /* config hash */ irc_request_t *request, /* the request */ int n) /* necessary arguments */{ if (request->paras < n) { irc_printf (sock, ":%s %03d %s " ERR_NEEDMOREPARAMS_TEXT "\n", conf->host, ERR_NEEDMOREPARAMS, client->nick, request->request); return -1; } return 0;}/* * This routine checks if a given client is away or not, then * sends this clients away message back to the client which requested * this. Return non-zero if away. */intirc_client_absent (irc_client_t *client, /* requested client */ irc_client_t *rclient) /* who want to know about */{ irc_config_t *cfg; svz_socket_t *sock; if (client->flag & UMODE_AWAY) { sock = rclient->sock; cfg = sock->cfg; irc_printf (sock, ":%s %03d %s " RPL_AWAY_TEXT "\n", cfg->host, RPL_AWAY, rclient->nick, client->nick, client->away); return -1; } return 0;}/* * This routine erases a client from all channels by a quit reason, * then the client is deleted itself. */intirc_leave_all_channels (irc_config_t *cfg, irc_client_t *client, char *reason){ irc_channel_t *channel; irc_client_t *cl; svz_socket_t *sock, *xsock; int i; sock = client->sock;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -