#define DEFAULT_CHANTYPES "#&"
#define DEFAULT_CHARSET "iso8859-15"
-void handle_005(struct network_state *s, struct line *l)
+void network_info_init(struct network_info *info)
+{
+ memset(info, 0, sizeof(struct network_info));
+ info->prefix = g_strdup(DEFAULT_PREFIX);
+ info->chantypes = g_strdup(DEFAULT_CHANTYPES);
+ info->charset = g_strdup(DEFAULT_CHARSET);
+}
+
+void free_network_info(struct network_info *info)
+{
+ g_free(info->prefix);
+ g_free(info->chantypes);
+ g_free(info->charset);
+ g_free(info->name);
+ g_free(info->server);
+ g_free(info->supported_user_modes);
+ g_free(info->supported_channel_modes);
+ g_strfreev(info->chanmodes);
+ g_free(info->chanlimit);
+ g_free(info->maxlist);
+ g_free(info->idchan);
+ g_free(info->statusmsg);
+}
+
+char *network_info_string(struct network_info *info)
{
- unsigned int i;
+ char *ret = NULL;
+ GList *fs = NULL, *gl;
+ char *casemap = NULL;
+
+ if (info->name != NULL)
+ fs = g_list_append(fs, g_strdup_printf("NETWORK=%s", info->name));
+
+ switch (info->casemapping) {
+ default:
+ case CASEMAP_RFC1459:
+ casemap = g_strdup("CASEMAPPING=rfc1459");
+ break;
+ case CASEMAP_STRICT_RFC1459:
+ casemap = g_strdup("CASEMAPPING=strict-rfc1459");
+ break;
+ case CASEMAP_ASCII:
+ casemap = g_strdup("CASEMAPPING=ascii");
+ break;
+ }
+
+ if (casemap != NULL)
+ fs = g_list_append(fs, casemap);
+
+ if (info->forced_nick_changes)
+ fs = g_list_append(fs, g_strdup("FNC"));
+
+ if (info->map)
+ fs = g_list_append(fs, "MAP");
+
+ if (info->charset != NULL)
+ fs = g_list_append(fs, g_strdup_printf("CHARSET=%s", info->charset));
+
+ if (info->nicklen != 0)
+ fs = g_list_append(fs, g_strdup_printf("NICKLEN=%d", info->nicklen));
+
+ if (info->userlen != 0)
+ fs = g_list_append(fs, g_strdup_printf("USERLEN=%d", info->userlen));
+
+ if (info->watch != 0)
+ fs = g_list_append(fs, g_strdup_printf("WATCH=%d", info->watch));
+
+ if (info->operoverride)
+ fs = g_list_append(fs, "OVERRIDE");
+
+ if (info->hostlen != 0)
+ fs = g_list_append(fs, g_strdup_printf("HOSTLEN=%d", info->hostlen));
+
+ if (info->channellen != 0)
+ fs = g_list_append(fs, g_strdup_printf("CHANNELLEN=%d", info->channellen));
+
+ if (info->awaylen != 0)
+ fs = g_list_append(fs, g_strdup_printf("AWAYLEN=%d", info->awaylen));
+
+ if (info->kicklen != 0)
+ fs = g_list_append(fs, g_strdup_printf("KICKLEN=%d", info->kicklen));
+
+ if (info->topiclen != 0)
+ fs = g_list_append(fs, g_strdup_printf("TOPICLEN=%d", info->topiclen));
+
+ if (info->maxchannels != 0)
+ fs = g_list_append(fs, g_strdup_printf("MAXCHANNELS=%d", info->maxchannels));
+
+ if (info->maxtargets != 0)
+ fs = g_list_append(fs, g_strdup_printf("MAXTARGETS=%d", info->maxtargets));
+
+ if (info->maxbans != 0)
+ fs = g_list_append(fs, g_strdup_printf("MAXBANS=%d", info->maxbans));
+
+ if (info->maxmodes != 0)
+ fs = g_list_append(fs, g_strdup_printf("MODES=%d", info->maxmodes));
+
+ if (info->maxpara != 0)
+ fs = g_list_append(fs, g_strdup_printf("MAXPARA=%d", info->maxpara));
+
+ if (info->wallchops)
+ fs = g_list_append(fs, g_strdup("WALLCHOPS"));
+
+ if (info->wallvoices)
+ fs = g_list_append(fs, g_strdup("WALLVOICES"));
+
+ if (info->rfc2812)
+ fs = g_list_append(fs, g_strdup("RFC2812"));
+
+ if (info->penalty)
+ fs = g_list_append(fs, g_strdup("PENALTY"));
+
+ if (info->remove)
+ fs = g_list_append(fs, g_strdup("REMOVE"));
+
+ if (info->safelist)
+ fs = g_list_append(fs, g_strdup("SAFELIST"));
- g_assert(s);
- g_assert(s->info);
- g_assert(l);
+ if (info->userip)
+ fs = g_list_append(fs, g_strdup("USERIP"));
- g_assert(l->argc >= 1);
+ if (info->capab)
+ fs = g_list_append(fs, g_strdup("CAPAB"));
+
+ if (info->cprivmsg)
+ fs = g_list_append(fs, g_strdup("CPRIVMSG"));
+
+ if (info->cnotice)
+ fs = g_list_append(fs, g_strdup("CNOTICE"));
+
+ if (info->knock)
+ fs = g_list_append(fs, g_strdup("KNOCK"));
+
+ if (info->vchannels)
+ fs = g_list_append(fs, g_strdup("VCHANNELS"));
- for(i = 3; i < l->argc-1; i++) {
- char *sep;
- char *key, *val;
+ if (info->whox)
+ fs = g_list_append(fs, g_strdup("WHOX"));
- g_assert(l->args[i]);
+ if (info->callerid)
+ fs = g_list_append(fs, g_strdup("CALLERID"));
+
+ if (info->accept)
+ fs = g_list_append(fs, g_strdup("ACCEPT"));
+
+ if (info->keylen != 0)
+ fs = g_list_append(fs, g_strdup_printf("KEYLEN=%d", info->keylen));
+
+ if (info->silence != 0)
+ fs = g_list_append(fs, g_strdup_printf("SILENCE=%d", info->silence));
+
+ if (info->chantypes != NULL)
+ fs = g_list_append(fs, g_strdup_printf("CHANTYPES=%s", info->chantypes));
+
+ if (info->chanmodes != NULL) {
+ char *tmp = g_strjoinv(",", info->chanmodes);
+ fs = g_list_append(fs, g_strdup_printf("CHANMODES=%s", tmp));
+ g_free(tmp);
+ }
- sep = strchr(l->args[i], '=');
+ if (info->chanlimit != NULL)
+ fs = g_list_append(fs, g_strdup_printf("CHANLIMIT=%s", info->chanlimit));
- if (!sep) {
- key = g_strdup(l->args[i]);
- val = NULL;
+ if (info->namesx)
+ fs = g_list_append(fs, "NAMESX");
+
+ if (info->securelist)
+ fs = g_list_append(fs, "SECURELIST");
+
+ if (info->excepts_mode != '\0')
+ fs = g_list_append(fs, g_strdup_printf("EXCEPTS=%c", info->excepts_mode));
+
+ if (info->statusmsg != NULL)
+ fs = g_list_append(fs, g_strdup_printf("STATUSMSG=%s", info->statusmsg));
+
+ if (info->invex_mode != '\0')
+ fs = g_list_append(fs, g_strdup_printf("INVEX=%c", info->invex_mode));
+
+ if (info->elist_mask_search ||
+ info->elist_inverse_mask_search ||
+ info->elist_usercount_search ||
+ info->elist_creation_time_search ||
+ info->elist_topic_search) {
+ char elist[100];
+ strcpy(elist, "");
+ if (info->elist_mask_search)
+ strncat(elist, "M", sizeof(elist));
+ if (info->elist_inverse_mask_search)
+ strncat(elist, "N", sizeof(elist));
+ if (info->elist_usercount_search)
+ strncat(elist, "U", sizeof(elist));
+ if (info->elist_creation_time_search)
+ strncat(elist, "C", sizeof(elist));
+ if (info->elist_topic_search)
+ strncat(elist, "T", sizeof(elist));
+ fs = g_list_append(fs, g_strdup_printf("ELIST=%s", elist));
+ }
+
+ if (info->deaf_mode != '\0')
+ fs = g_list_append(fs, g_strdup_printf("DEAF=%c", info->deaf_mode));
+
+ if (info->maxlist != NULL)
+ fs = g_list_append(fs, g_strdup_printf("MAXLIST=%s", info->maxlist));
+
+ if (info->idchan != NULL)
+ fs = g_list_append(fs, g_strdup_printf("IDCHAN=%s", info->idchan));
+
+ if (info->prefix != NULL)
+ fs = g_list_append(fs, g_strdup_printf("PREFIX=%s", info->prefix));
+
+ ret = list_make_string(fs);
+
+ for (gl = fs; gl; gl = gl->next)
+ g_free(gl->data);
+
+ g_list_free(fs);
+
+ return ret;
+}
+
+void network_info_parse(struct network_info *info, const char *parameter)
+{
+ char *sep;
+ char *key, *val;
+
+ sep = strchr(parameter, '=');
+
+ if (!sep) {
+ key = g_strdup(parameter);
+ val = NULL;
+ } else {
+ key = g_strndup(parameter, sep - parameter);
+ val = g_strdup(sep+1);
+ }
+
+ if(!g_strcasecmp(key, "CASEMAPPING")) {
+ if(!g_strcasecmp(val, "rfc1459")) {
+ info->casemapping = CASEMAP_RFC1459;
+ } else if(!g_strcasecmp(val, "strict-rfc1459")) {
+ info->casemapping = CASEMAP_STRICT_RFC1459;
+ } else if(!g_strcasecmp(val, "ascii")) {
+ info->casemapping = CASEMAP_ASCII;
} else {
- key = g_strndup(l->args[i], sep - l->args[i]);
- val = g_strdup(sep+1);
+ info->casemapping = CASEMAP_UNKNOWN;
+ log_global(LOG_WARNING, "Unknown CASEMAPPING value '%s'", val);
}
-
- g_hash_table_replace(s->info->features, key, val);
-
- if(!g_strcasecmp(key, "CASEMAPPING")) {
- if(!g_strcasecmp(val, "rfc1459")) {
- s->info->casemapping = CASEMAP_RFC1459;
- } else if(!g_strcasecmp(val, "strict-rfc1459")) {
- s->info->casemapping = CASEMAP_STRICT_RFC1459;
- } else if(!g_strcasecmp(val, "ascii")) {
- s->info->casemapping = CASEMAP_ASCII;
- } else {
- s->info->casemapping = CASEMAP_UNKNOWN;
- log_network_state(NULL, LOG_WARNING, s, "Unknown CASEMAPPING value '%s'", val);
+ } else if (!g_strcasecmp(key, "NETWORK")) {
+ g_free(info->name);
+ info->name = g_strdup(val);
+ } else if (!g_strcasecmp(key, "NICKLEN") || !g_strcasecmp(key, "MAXNICKLEN")) {
+ info->nicklen = atoi(val);
+ } else if (!g_strcasecmp(key, "USERLEN")) {
+ info->userlen = atoi(val);
+ } else if (!g_strcasecmp(key, "HOSTLEN")) {
+ info->hostlen = atoi(val);
+ } else if (!g_strcasecmp(key, "OVERRIDE")) {
+ info->operoverride = TRUE;
+ } else if (!g_strcasecmp(key, "CHANNELLEN") || !g_strcasecmp(key, "MAXCHANNELLEN")) {
+ info->channellen = atoi(val);
+ } else if (!g_strcasecmp(key, "AWAYLEN")) {
+ info->awaylen = atoi(val);
+ } else if (!g_strcasecmp(key, "KICKLEN")) {
+ info->kicklen = atoi(val);
+ } else if (!g_strcasecmp(key, "TOPICLEN")) {
+ info->topiclen = atoi(val);
+ } else if (!g_strcasecmp(key, "WATCH")) {
+ info->watch = atoi(val);
+ } else if (!g_strcasecmp(key, "MAXPARA")) {
+ info->maxpara = atoi(val);
+ } else if (!g_strcasecmp(key, "MAXCHANNELS")) {
+ info->maxchannels = atoi(val);
+ } else if (!g_strcasecmp(key, "MAXTARGETS")) {
+ info->maxtargets = atoi(val);
+ } else if (!g_strcasecmp(key, "REMOVE")) {
+ info->remove = TRUE;
+ } else if (!g_strcasecmp(key, "MAXBANS")) {
+ info->maxbans = atoi(val);
+ } else if (!g_strcasecmp(key, "MODES")) {
+ info->maxmodes = atoi(val);
+ } else if (!g_strcasecmp(key, "WALLCHOPS")) {
+ info->wallchops = TRUE;
+ } else if (!g_strcasecmp(key, "MAP")) {
+ info->map = TRUE;
+ } else if (!g_strcasecmp(key, "WALLVOICES")) {
+ info->wallvoices = TRUE;
+ } else if (!g_strcasecmp(key, "RFC2812")) {
+ info->rfc2812 = TRUE;
+ } else if (!g_strcasecmp(key, "PENALTY")) {
+ info->penalty = TRUE;
+ } else if (!g_strcasecmp(key, "FNC")) {
+ info->forced_nick_changes = TRUE;
+ } else if (!g_strcasecmp(key, "SAFELIST")) {
+ info->safelist = TRUE;
+ } else if (!g_strcasecmp(key, "USERIP")) {
+ info->userip = TRUE;
+ } else if (!g_strcasecmp(key, "CPRIVMSG")) {
+ info->cprivmsg = TRUE;
+ } else if (!g_strcasecmp(key, "CNOTICE")) {
+ info->cnotice = TRUE;
+ } else if (!g_strcasecmp(key, "KNOCK")) {
+ info->knock = TRUE;
+ } else if (!g_strcasecmp(key, "CAPAB")) {
+ info->capab = TRUE;
+ } else if (!g_strcasecmp(key, "VCHANNELS")) {
+ info->vchannels = TRUE;
+ } else if (!g_strcasecmp(key, "WHOX")) {
+ info->whox = TRUE;
+ } else if (!g_strcasecmp(key, "CALLERID")) {
+ info->callerid = TRUE;
+ } else if (!g_strcasecmp(key, "ACCEPT")) {
+ info->accept = TRUE;
+ } else if (!g_strcasecmp(key, "KEYLEN")) {
+ info->keylen = atoi(val);
+ } else if (!g_strcasecmp(key, "SILENCE")) {
+ info->silence = atoi(val);
+ } else if (!g_strcasecmp(key, "CHANTYPES")) {
+ g_free(info->chantypes);
+ info->chantypes = g_strdup(val);
+ } else if (!g_strcasecmp(key, "CHANMODES")) {
+ g_strfreev(info->chanmodes);
+ info->chanmodes = g_strsplit(val, ",", 4);
+ /* FIXME: Make sure info->chanmodes length is exactly 4 */
+ } else if (!g_strcasecmp(key, "CHANLIMIT")) {
+ g_free(info->chanlimit);
+ info->chanlimit = g_strdup(val);
+ } else if (!g_strcasecmp(key, "EXCEPTS")) {
+ if (val == NULL)
+ info->excepts_mode = 'e';
+ else if (strlen(val) > 1)
+ log_global(LOG_WARNING, "Invalid length excepts value: %s", val);
+ else
+ info->excepts_mode = val[0];
+ } else if (!g_strcasecmp(key, "INVEX")) {
+ if (val == NULL)
+ info->invex_mode = 'I';
+ else if (strlen(val) > 1)
+ log_global(LOG_WARNING, "Invalid length invex value: %s", val);
+ else
+ info->invex_mode = val[0];
+ } else if (!g_strcasecmp(key, "ELIST")) {
+ int i;
+ for (i = 0; val[i]; i++) {
+ switch (val[i]) {
+ case 'M': info->elist_mask_search = TRUE; break;
+ case 'N': info->elist_inverse_mask_search = TRUE; break;
+ case 'T': info->elist_topic_search = TRUE; break;
+ case 'U': info->elist_usercount_search = TRUE; break;
+ case 'C': info->elist_creation_time_search = TRUE; break;
+ default:
+ log_global(LOG_WARNING, "Unknown ELIST parameter '%c'", val[i]);
+ break;
}
- } else if(!g_strcasecmp(key, "NETWORK")) {
- g_free(s->info->name);
- s->info->name = g_strdup(val);
- }
+ }
+ } else if (!g_strcasecmp(key, "DEAF")) {
+ if (val == NULL)
+ info->deaf_mode = 'D';
+ else if (strlen(val) > 1)
+ log_global(LOG_WARNING, "Invalid length deaf value: %s", val);
+ else
+ info->deaf_mode = val[0];
+ } else if (!g_strcasecmp(key, "MAXLIST")) {
+ g_free(info->maxlist);
+ info->maxlist = g_strdup(val);
+ } else if (!g_strcasecmp(key, "IDCHAN")) {
+ g_free(info->idchan);
+ info->idchan = g_strdup(val);
+ } else if (!g_strcasecmp(key, "STATUSMSG")) {
+ g_free(info->statusmsg);
+ info->statusmsg = g_strdup(val);
+ } else if (!g_strcasecmp(key, "PREFIX")) {
+ g_free(info->prefix);
+ info->prefix = g_strdup(val);
+ } else if (!g_strcasecmp(key, "CHARSET")) {
+ g_free(info->charset);
+ info->charset = g_strdup(val);
+ } else if (!g_strcasecmp(key, "NAMESX")) {
+ info->namesx = TRUE;
+ } else if (!g_strcasecmp(key, "SECURELIST")) {
+ info->securelist = TRUE;
+ } else {
+ log_global(LOG_WARNING, "Unknown 005 parameter `%s'", key);
}
+ g_free(key);
+ g_free(val);
}
-gboolean network_supports(const struct network_info *n, const char *fe)
+void handle_005(struct network_state *s, struct line *l)
{
- gpointer k, v;
- g_assert(n);
- g_assert(n->features);
- return g_hash_table_lookup_extended (n->features, fe, &k, &v);
+ int i;
+ g_assert(s);
+ g_assert(l);
+
+ g_assert(l->argc >= 1);
+
+ for (i = 3; i < l->argc-1; i++)
+ network_info_parse(&s->info, l->args[i]);
}
int irccmp(const struct network_info *n, const char *a, const char *b)
{
- switch(n?n->casemapping:CASEMAP_UNKNOWN) {
+ switch(n != NULL?n->casemapping:CASEMAP_UNKNOWN) {
default:
case CASEMAP_UNKNOWN:
case CASEMAP_RFC1459:
gboolean is_channelname(const char *name, const struct network_info *n)
{
- const char *chantypes = NULL;
+ g_assert(n != NULL);
+ g_assert(n->chantypes != NULL);
- g_assert(name);
-
- if (n != NULL) {
- g_assert(n->features);
+ g_assert(name != NULL);
- chantypes = g_hash_table_lookup(n->features, "CHANTYPES");
- }
-
- if(chantypes == NULL)
- chantypes = DEFAULT_CHANTYPES;
-
- if(strchr(chantypes, name[0]))
+ if (strchr(n->chantypes, name[0]))
return TRUE;
return FALSE;
gboolean is_prefix(char p, const struct network_info *n)
{
- const char *prefix = NULL;
const char *pref_end;
- if (n != NULL) {
- g_assert(n->features);
- prefix = g_hash_table_lookup(n->features, "PREFIX");
- }
-
- if (prefix == NULL)
- prefix = DEFAULT_PREFIX;
+ g_assert(n != NULL);
+ g_assert(n->prefix != NULL);
- pref_end = strchr(prefix, ')');
- if (!pref_end)pref_end = prefix; else pref_end++;
+ pref_end = strchr(n->prefix, ')');
+ if (!pref_end)pref_end = n->prefix; else pref_end++;
if(strchr(pref_end, p)) return TRUE;
return FALSE;
const char *get_charset(const struct network_info *n)
{
- char *ret = g_hash_table_lookup(n->features, "CHARSET");
-
- if (ret != NULL)
- return ret;
-
- return DEFAULT_CHARSET;
+ g_assert(n != NULL);
+ return n->charset;
}
char get_prefix_by_mode(char mode, const struct network_info *n)
{
- const char *prefix = NULL;
int i;
char *pref_end;
+ const char *prefix;
+
+ g_assert(n != NULL);
+ g_assert(n->prefix != NULL);
- if (n != NULL) {
- g_assert(n->features);
-
- prefix = g_hash_table_lookup(n->features, "PREFIX");
- }
-
- if (prefix == NULL)
- prefix = DEFAULT_PREFIX;
+ prefix = n->prefix;
pref_end = strchr(prefix, ')');
if(prefix[0] != '(' || !pref_end) {
- log_global(NULL, LOG_WARNING, "Malformed PREFIX data `%s'", prefix);
+ log_global(LOG_WARNING, "Malformed PREFIX data `%s'", prefix);
return ' ';
}
pref_end++;
}
return ' ';
}
+
+const static char *default_chanmodes[] = {
+ "beI", "k" , "l" , "imnpsta"
+};
+
+int network_chanmode_type(char m, struct network_info *n)
+{
+ int i;
+ for (i = 0; i < 4; i++) {
+ if (strchr((n && n->chanmodes)?n->chanmodes[i]:default_chanmodes[i], m)) {
+ return i;
+ }
+ }
+
+ return 3;
+}