/* Conversion routines for HybServ. * * IRC Services is copyright (c) 1996-2007 Andrew Church. * E-mail: * Parts written by Andrew Kempe and others. * This program is free but copyrighted software; see the file COPYING for * details. */ #include "convert-db.h" /*************************************************************************/ /* Encrypted passwords in use? (-crypt option) */ static int crypted_passwords = 0; /*************************************************************************/ /*************************************************************************/ /* Get the next parameter, which may be a colon-prefixed rest-of-the-line * parameter. As with strtok(), a NULL parameter means "continue from the * last call". */ static inline char *next_token(char *s) { static char *str = NULL; char *res; if (s) str = s; if (!str) return NULL; str += strspn(str, " \r\n"); if (!*str) { str = NULL; return NULL; } if (*str == ':') { res = str+1; str += strcspn(str, "\r\n"); *str = 0; str = NULL; } else { res = str; str += strcspn(str, " \r\n"); if (*str) *str++ = 0; } return res; } /*************************************************************************/ /* Nickname flag conversion table (zero-terminated) */ static const struct { int32 hybflag; /* HybServ flag value */ int32 nf; /* Flags to set in ngi->flags */ int32 ns; /* Flags to set in ni->status */ } hyb_nickflags[] = { { 0x00000001, 0, 0 }, /* NS_IDENTIFIED */ { 0x00000002, NF_KILLPROTECT, 0 }, /* NS_PROTECTED */ /* NS_OPERATOR: operator-owned nick, doesn't expire */ { 0x00000004, 0, NS_NOEXPIRE }, /* NS_AUTOMASK: automatically add new hostmasks to ACCESS list */ { 0x00000008, 0, 0 }, { 0x00000010, NF_PRIVATE, 0 }, /* NS_PRIVATE */ { 0x00000020, 0, 0 }, /* NS_COLLIDE */ { 0x00000040, 0, 0 }, /* NS_RELEASE */ { 0x00000080, 0, NS_VERBOTEN }, /* NS_FORBID */ { 0x00000100, NF_SECURE, 0 }, /* NS_SECURE */ { 0x00000200, 0, 0 }, /* NS_DELETE */ /* NS_UNSECURE: like !SECURE, but assume IDENTIFIED on access match */ { 0x00000400, 0, 0 }, { 0x00000800, NF_MEMO_SIGNON, 0 }, /* NS_MEMOSIGNON */ { 0x00001000, NF_MEMO_RECEIVE, 0 }, /* NS_MEMONOTIFY */ /* NS_MEMOS: allow memos to be sent to us (handled separately) */ { 0x00002000, 0, 0 }, { 0x00004000, NF_HIDE_EMAIL|NF_HIDE_MASK|NF_HIDE_QUIT, 0 }, /*NS_HIDEALL*/ { 0x00008000, NF_HIDE_EMAIL, 0 }, /* NS_HIDEEMAIL */ { 0x00010000, 0, 0 }, /* NS_HIDEURL */ { 0x00020000, NF_HIDE_QUIT, 0 }, /* NS_HIDEQUIT */ { 0x00040000, NF_HIDE_MASK, 0 }, /* NS_HIDEADDR */ { 0x00080000, NF_KILL_IMMED, 0 }, /* NS_KILLIMMED */ /* NS_NOREGISTER: not allowed to register channels */ { 0x00100000, 0, 0 }, /* NS_NOCHANOPS: not allowed to get chanops */ { 0x00200000, 0, 0 }, /* NS_TFORBID: temporary forbid (expiration time in ni->lastseen) */ { 0x00400000, 0, 0 }, { 0 } }; static void hyb_load_nick(const char *sourcedir) { FILE *f; char fname[PATH_MAX+1]; char buf[4096]; /* HybServ uses MAXLINE (510); let's be safe */ char *s; NickInfo *ni = NULL; NickGroupInfo *ngi = NULL; int line; snprintf(fname, sizeof(fname), "%s/nick.db", sourcedir); f = fopen(fname, "r"); if (!f) { fprintf(stderr, "Cannot open %s: %s\n", fname, strerror(errno)); exit(1); } line = 0; while (fgets(buf, sizeof(buf), f)) { line++; if (!(s = next_token(buf))) continue; if (*s == ';') continue; if (strncmp(s, "->", 2) != 0) { /* New nickname */ char *s2, *s3, *nick = s; long flags, timereg, lastseen; #ifdef CLEAN_COMPILE flags = timereg = lastseen = 0; #endif ni = NULL; ngi = NULL; s = next_token(NULL); if (s) flags = strtol(s, &s, 10); s2 = next_token(NULL); if (s2) timereg = strtol(s2, &s2, 10); s3 = next_token(NULL); if (s3) lastseen = strtol(s3, &s3, 10); if (!s || !s2 || !s3 || *s || *s2 || *s3) { fprintf(stderr, "%s:%d: Invalid nickname line, ignoring" " nick %s\n", fname, line, nick); } else if (get_nickinfo(nick)) { fprintf(stderr, "%s:%d: Nickname `%s' already exists," " skipping\n", fname, line, nick); } else { int i; if (strlen(nick) > NICKMAX-1) { fprintf(stderr, "%s:%d: Nickname %s truncated to %d" " characters\n", fname, line, nick, NICKMAX-1); nick[NICKMAX-1] = 0; } ni = makenick(nick, &ngi); ni->time_registered = (time_t)timereg; ni->last_seen = (time_t)lastseen; for (i = 0; hyb_nickflags[i].hybflag; i++) { if (flags & hyb_nickflags[i].hybflag) { ngi->flags |= hyb_nickflags[i].nf; ni->status |= hyb_nickflags[i].ns; } } if (!(flags & 0x2000)) /* NS_MEMOS */ ngi->memos.memomax = 0; if (ni->status & NS_VERBOTEN) { /* Forbidden nick, so delete the nickgroup */ ni->nickgroup = 0; del_nickgroupinfo(ngi); ngi = NULL; } } /* if valid nickname line */ } else if (ni) { /* Parameter for the current nickname */ s += 2; if (stricmp(s, "PASS") == 0) { if (ngi) { if (*ngi->pass) { fprintf(stderr, "%s:%d: Duplicate PASS line," " ignoring\n", fname, line); } else { char *pass = next_token(NULL); if (!pass || !*pass) { fprintf(stderr, "%s:%d: Corrupt PASS line, setting" " password to nickname for %s\n", fname, line, ni->nick); if (crypted_passwords) { #ifdef SERVICES_5_1 pass = crypt(ni->nick, "xx"); if (!pass) { perror("FATAL: crypt() failed"); exit(1); } #endif } else { pass = ni->nick; } } if (strlen(pass) > sizeof(ngi->pass)-1) { if (crypted_passwords) { fprintf(stderr, "FATAL: PASSMAX too small for" " encrypted passwords!\n"); exit(1); } else { fprintf(stderr, "%s:%d: Password for `%s'" " truncated to %d characters\n", fname, line, ni->nick, sizeof(ngi->pass)-1); } } strscpy(ngi->pass, pass, sizeof(ngi->pass)); #ifdef SERVICES_5_1 ngi->pass.cipher = sstrdup("unix-crypt"); #endif } } } else if (stricmp(s, "PERMPASS") == 0) { /* ignore */ } else if (stricmp(s, "HOST") == 0) { if (ngi) { s = next_token(NULL); if (!s) { fprintf(stderr, "%s:%d: Corrupt HOST line, ignoring\n", fname, line); } else { ARRAY_EXTEND(ngi->access); ngi->access[ngi->access_count-1] = sstrdup(s); } } } else if (stricmp(s, "EMAIL") == 0) { if (ngi) { s = next_token(NULL); if (!s) { fprintf(stderr, "%s:%d: Corrupt EMAIL line," " ignoring\n", fname, line); } else if (ngi->email) { fprintf(stderr, "%s:%d: Duplicate EMAIL line," " ignoring\n", fname, line); } else { ngi->email = sstrdup(s); } } } else if (stricmp(s, "URL") == 0) { if (ngi) { s = next_token(NULL); if (!s) { fprintf(stderr, "%s:%d: Corrupt URL line," " ignoring\n", fname, line); } else if (ngi->url) { fprintf(stderr, "%s:%d: Duplicate URL line," " ignoring\n", fname, line); } else { ngi->url = sstrdup(s); } } } else if (stricmp(s, "LASTUH") == 0) { char *user = next_token(NULL); char *host = next_token(NULL); char buf[1024]; if (!user || !host) { fprintf(stderr, "%s:%d: Corrupt LASTUH line," " ignoring\n", fname, line); } else { snprintf(buf, sizeof(buf), "%s@%s", user, host); if (ni->last_usermask) { fprintf(stderr, "%s:%d: Duplicate LASTUH line," " ignoring\n", fname, line); } else { ni->last_usermask = sstrdup(buf); ni->last_realmask = sstrdup(buf); } } } else if (stricmp(s, "LASTQMSG") == 0) { s = next_token(NULL); if (!s) { fprintf(stderr, "%s:%d: Corrupt LASTQMSG line," " ignoring\n", fname, line); } else if (ni->last_quit) { fprintf(stderr, "%s:%d: Duplicate LASTQMSG line," " ignoring\n", fname, line); } else { ni->last_quit = sstrdup(s); } } else if (stricmp(s, "ICQ") == 0 || stricmp(s, "UIN") == 0) { /* ignore */ } else if (stricmp(s, "GSM") == 0) { /* ignore */ } else if (stricmp(s, "PHONE") == 0) { /* ignore */ } else if (stricmp(s, "LANG") == 0) { /* ignore */ } else if (stricmp(s, "FREASON") == 0) { /* ignore */ } else if (stricmp(s, "FTIME") == 0) { /* ignore */ } else if (stricmp(s, "LINK") == 0) { char *master = next_token(NULL); NickInfo *ni2; NickGroupInfo *ngi2; if (strlen(master) > NICKMAX-1) master[NICKMAX-1] = 0; /* Link targets are always written before the link itself */ if (!(ni2 = get_nickinfo(master))) { fprintf(stderr, "%s:%d: Master nick %s for nickname %s" " is missing\n", fname, line, master, ni->nick); } else if (!(ngi2 = get_nickgroupinfo(ni2->nickgroup))) { fprintf(stderr, "%s:%d: Nickgroup missing for master" " nick %s, ignoring link\n", fname, line, master); } else { del_nickgroupinfo(ngi); ngi = NULL; ni->nickgroup = ngi2->id; ARRAY_EXTEND(ngi2->nicks); strscpy(ngi2->nicks[ngi2->nicks_count-1], ni->nick, sizeof(*ngi2->nicks)); } } else { static int warnings = 0; switch (warnings) { case 5: fprintf(stderr, "%s:%d: More unrecognized nickname" " options follow\n", fname, line); warnings = -1; /* fall through */ case -1: break; default: fprintf(stderr, "%s:%d: Unrecognized nickname option" " `%s'\n", fname, line, s); warnings++; break; } } } /* nick parameters */ } /* while (fgets()) */ fclose(f); } /*************************************************************************/ /* Channel flag conversion table (zero-terminated) */ static const struct { int32 hybflag; /* HybServ flag value */ int32 cf; /* Flags to set in ci->flags */ } hyb_chanflags[] = { { 0x00000001, CI_PRIVATE, }, /* CS_PRIVATE */ { 0x00000002, CI_TOPICLOCK }, /* CS_TOPICLOCK */ { 0x00000004, CI_SECURE }, /* CS_SECURE */ { 0x00000008, CI_SECUREOPS }, /* CS_SECUREOPS */ { 0x00000010, 0 }, /* CS_SUSPENDED (handled separately) */ { 0x00000020, CI_VERBOTEN }, /* CS_FORBID */ { 0x00000040, CI_RESTRICTED }, /* CS_RESTRICTED */ { 0x00000080, 0 }, /* CS_FORGET */ { 0x00000100, 0 }, /* CS_DELETE */ { 0x00000200, CI_NOEXPIRE }, /* CS_NOEXPIRE */ { 0x00000400, 0 }, /* CS_GUARD (ChanServ join) */ /* 1.7.3 and later: CS_SPLITOPS--same as LEAVEOPS * 1.6.1+UniBG: CS_TFORBID--temporary forbid (expiration time in * ci->lastused) * We differentiate between these by whether CS_FORBID is also set * (+UniBG always sets CS_FORBID with CS_TFORBID) */ { 0x00000800, 0 }, { 0 } }; /* Channel mode conversion table */ static struct { int32 flag; char mode; } cmodes[] = { { 0x00000010, 'l' }, { 0x00000020, 'k' }, { 0x00000040, 's' }, { 0x00000080, 'p' }, { 0x00000100, 'n' }, { 0x00000200, 't' }, { 0x00000400, 'm' }, { 0x00000800, 'i' }, { 0, 0 } }; static void hyb_load_chan(const char *sourcedir) { FILE *f; char fname[PATH_MAX+1]; char buf[4096]; /* HybServ uses MAXLINE (510); let's be safe */ char *s; ChannelInfo *ci = NULL; int line; snprintf(fname, sizeof(fname), "%s/chan.db", sourcedir); f = fopen(fname, "r"); if (!f) { fprintf(stderr, "Cannot open %s: %s\n", fname, strerror(errno)); exit(1); } line = 0; while (fgets(buf, sizeof(buf), f)) { line++; if (!(s = next_token(buf))) continue; if (*s == ';') continue; if (strncmp(s, "->", 2) != 0) { /* New channel */ char *s2, *s3, *channel = s; long flags, timereg, lastused; #ifdef CLEAN_COMPILE flags = timereg = lastused = 0; #endif /* The previous channel hasn't been added to the database yet */ if (ci) { if (ci->founder) { add_channelinfo(ci); } else { fprintf(stderr, "%s:%d: Channel %s has no founder," " skipping\n", fname, line, ci->name); } } ci = NULL; s = next_token(NULL); if (s) flags = strtol(s, &s, 10); s2 = next_token(NULL); if (s2) timereg = strtol(s2, &s2, 10); s3 = next_token(NULL); if (s3) lastused = strtol(s3, &s3, 10); if (*channel!='#' || !s || !s2 || !s3 || *s || *s2 || *s3) { fprintf(stderr, "%s:%d: Invalid channel line, ignoring" " channel %s\n", fname, line, channel); } else if (strcmp(channel, "#") == 0) { fprintf(stderr, "%s:%d: Channel `#' not supported in IRC" " Services, ignoring\n", fname, line); } else if (get_channelinfo(channel)) { fprintf(stderr, "%s:%d: Channel `%s' already exists," " skipping\n", fname, line, channel); } else if (flags & 0x80) { /* CS_FORGET */ fprintf(stderr, "%s:%d: Skipping forgotten channel %s\n", fname, line, channel); } else { int i; if (strlen(channel) > CHANMAX-1) { fprintf(stderr, "%s:%d: Channel %s truncated to %d" " characters\n", fname, line, channel, NICKMAX-1); channel[CHANMAX-1] = 0; } ci = makechan(channel); ci->time_registered = (time_t)timereg; ci->last_used = (time_t)lastused; for (i = 0; hyb_chanflags[i].hybflag; i++) { if (flags & hyb_chanflags[i].hybflag) ci->flags |= hyb_chanflags[i].cf; } if (flags & 0x10) { /* CS_SUSPENDED */ ci->suspendinfo = new_suspendinfo( "", "Unknown (imported from HybServ)", 0 ); } if (flags & 0x800) { /* CS_TFORBID or CS_SPLITOPS */ if (flags & 0x20) { /* Forbidden channel, so it must be CS_TFORBID; * we don't support TFORBID, so do nothing */ } else { /* Non-forbidden channel, so it must be CS_SPLITOPS */ ci->flags |= CI_LEAVEOPS; } } } /* if valid channel line */ } else if (ci) { /* Parameter for the current channel */ s += 2; if (stricmp(s, "FNDR") == 0) { NickInfo *ni; if (ci->founder) { fprintf(stderr, "%s:%d: Duplicate FNDR line, ignoring\n", fname, line); } else { s = next_token(NULL); if (!(ni = get_nickinfo(s))) { fprintf(stderr, "%s:%d: Nonexistent nick %s for" " founder of %s\n", fname, line, s, ci->name); } else if (ni->status & NS_VERBOTEN) { fprintf(stderr, "%s:%d: Forbidden nick %s for" " founder of %s\n", fname, line, s, ci->name); } else { ci->founder = ni->nickgroup; } } } else if (stricmp(s, "SUCCESSOR") == 0) { NickInfo *ni; if (ci->successor) { fprintf(stderr, "%s:%d: Duplicate SUCCESSOR line," " ignoring\n", fname, line); } else { s = next_token(NULL); if (!(ni = get_nickinfo(s))) { fprintf(stderr, "%s:%d: Nonexistent nick %s for" " successor of %s\n", fname, line, s, ci->name); } else if (ni->status & NS_VERBOTEN) { fprintf(stderr, "%s:%d: Forbidden nick %s for" " successor of %s\n", fname, line, s, ci->name); } else if (ni->nickgroup == ci->founder) { fprintf(stderr, "%s:%d: Successor of %s is the same" " as the founder, ignoring\n", fname, line, ci->name); } else { ci->successor = ni->nickgroup; } } } else if (stricmp(s, "PASS") == 0) { if (*ci->founderpass) { fprintf(stderr, "%s:%d: Duplicate PASS line, ignoring\n", fname, line); } else { char *pass = next_token(NULL); if (!pass || !*pass) { fprintf(stderr, "%s:%d: Corrupt PASS line, setting" " password to channel name for %s\n", fname, line, ci->name); if (crypted_passwords) { #ifdef SERVICES_5_1 pass = crypt(ci->name, "xx"); if (!pass) { perror("FATAL: crypt() failed"); exit(1); } #endif } else { pass = ci->name; } } if (strlen(pass) > sizeof(ci->founderpass)-1) { if (crypted_passwords) { fprintf(stderr, "FATAL: PASSMAX too small for" " encrypted passwords!\n"); exit(1); } else { fprintf(stderr, "%s:%d: Password for `%s'" " truncated to %d characters\n", fname, line, ci->name, sizeof(ci->founderpass)-1); } } strscpy(ci->founderpass, pass, sizeof(ci->founderpass)); #ifdef SERVICES_5_1 ci->founderpass.cipher = sstrdup("unix-crypt"); #endif } } else if (stricmp(s, "PERMPASS") == 0) { /* ignore */ } else if (stricmp(s, "ACCESS") == 0) { char *nick = next_token(NULL); char *level_s = next_token(NULL); /* Next parameter (nick who added entry) might be missing; * currently not used */ long level; NickInfo *ni; #ifdef CLEAN_COMPILE level = 0; #endif if (level_s) level = strtol(level_s, &level_s, 10); if (!level_s || *level_s) { fprintf(stderr, "%s:%d: Corrupt ACCESS line, ignoring\n", fname, line); } else if (!(ni = get_nickinfo(nick))) { fprintf(stderr, "%s:%d: ACCESS line for nonexistent nick," " ignoring\n", fname, line); } else if (ni->status & NS_VERBOTEN) { fprintf(stderr, "%s:%d: ACCESS line for forbidden nick," " ignoring\n", fname, line); } else if (ni->nickgroup != ci->founder) { ARRAY_EXTEND(ci->access); ci->access[ci->access_count-1].nickgroup = ni->nickgroup; if (level < -9999) level = -999; if (level < -9) level = level/10; else if (level < 0) level = -1; else if (level < 5) level = level*6; else if (level < 10) level = 10 + level*4; else if (level < 15) level = -50 + level*10; else if (level < 20) level = 70 + level*2; else if (level < 200) level = 100 + level/2; else if (level < 1000) level = 175 + level/8; else if (level < 9000) level = 300 + (level-1000)*600/8000; else if (level < 10000) level = level/10; else level = 999; ci->access[ci->access_count-1].level = (int)level; } } else if (stricmp(s, "AKICK") == 0) { char *mask = next_token(NULL); char *reason = next_token(NULL); if (!reason) { fprintf(stderr, "%s:%d: Corrupt AKICK line, ignoring\n", fname, line); } else { ARRAY_EXTEND(ci->akick); ci->akick[ci->akick_count-1].mask = sstrdup(mask); ci->akick[ci->akick_count-1].reason = sstrdup(reason); strscpy(ci->akick[ci->akick_count-1].who, "", sizeof(ci->akick[ci->akick_count-1].who)); ci->akick[ci->akick_count-1].set = time(NULL); ci->akick[ci->akick_count-1].lastused = 0; } } else if (stricmp(s, "ALVL") == 0) { /* ignore */ } else if (stricmp(s, "TOPIC") == 0) { s = next_token(NULL); if (!s) { fprintf(stderr, "%s:%d: Corrupt TOPIC line," " ignoring\n", fname, line); } else if (ci->last_topic) { fprintf(stderr, "%s:%d: Duplicate TOPIC line," " ignoring\n", fname, line); } else { ci->last_topic = sstrdup(s); strscpy(ci->last_topic_setter, "", sizeof(ci->last_topic_setter)); ci->last_topic_time = time(NULL); } } else if (stricmp(s, "LIMIT") == 0) { long limit; #ifdef CLEAN_COMPILE limit = 0; #endif s = next_token(NULL); if (s) limit = strtol(s, &s, 10); if (!s || *s) { fprintf(stderr, "%s:%d: Corrupt LIMIT line," " ignoring\n", fname, line); } else if (limit < 1) { fprintf(stderr, "%s:%d: Limit out of range," " ignoring\n", fname, line); } else if (ci->mlock_limit) { fprintf(stderr, "%s:%d: Duplicate LIMIT line," " ignoring\n", fname, line); } else { ci->mlock_limit = limit; } } else if (stricmp(s, "KEY") == 0) { s = next_token(NULL); if (!s) { fprintf(stderr, "%s:%d: Corrupt KEY line," " ignoring\n", fname, line); } else if (ci->mlock_key) { fprintf(stderr, "%s:%d: Duplicate KEY line," " ignoring\n", fname, line); } else { ci->mlock_key = sstrdup(s); } } else if (stricmp(s, "MON") == 0) { long modes; #ifdef CLEAN_COMPILE modes = 0; #endif s = next_token(NULL); if (s) modes = strtol(s, &s, 10); if (!s || *s) { fprintf(stderr, "%s:%d: Corrupt MON line," " ignoring\n", fname, line); } else if (ci->mlock_on) { fprintf(stderr, "%s:%d: Duplicate MON line," " ignoring\n", fname, line); } else { int i; ci->mlock_on = s = scalloc(64, 1); for (i = 0; cmodes[i].flag != 0; i++) { if (modes & cmodes[i].flag) *s++ = cmodes[i].mode; } *s = 0; } } else if (stricmp(s, "MOFF") == 0) { long modes; #ifdef CLEAN_COMPILE modes = 0; #endif s = next_token(NULL); if (s) modes = strtol(s, &s, 10); if (!s || *s) { fprintf(stderr, "%s:%d: Corrupt MOFF line," " ignoring\n", fname, line); } else if (ci->mlock_off) { fprintf(stderr, "%s:%d: Duplicate MOFF line," " ignoring\n", fname, line); } else { int i; ci->mlock_off = s = scalloc(64, 1); for (i = 0; cmodes[i].flag != 0; i++) { if (modes & cmodes[i].flag) *s++ = cmodes[i].mode; } *s = 0; } } else if (stricmp(s, "ENTRYMSG") == 0) { s = next_token(NULL); if (!s) { fprintf(stderr, "%s:%d: Corrupt ENTRYMSG line," " ignoring\n", fname, line); } else if (ci->entry_message) { fprintf(stderr, "%s:%d: Duplicate ENTRYMSG line," " ignoring\n", fname, line); } else { ci->entry_message = sstrdup(s); } } else if (stricmp(s, "EMAIL") == 0) { s = next_token(NULL); if (!s) { fprintf(stderr, "%s:%d: Corrupt EMAIL line," " ignoring\n", fname, line); } else if (ci->email) { fprintf(stderr, "%s:%d: Duplicate EMAIL line," " ignoring\n", fname, line); } else { ci->email = sstrdup(s); } } else if (stricmp(s, "URL") == 0) { s = next_token(NULL); if (!s) { fprintf(stderr, "%s:%d: Corrupt URL line," " ignoring\n", fname, line); } else if (ci->url) { fprintf(stderr, "%s:%d: Duplicate URL line," " ignoring\n", fname, line); } else { ci->url = sstrdup(s); } } else if (stricmp(s, "FREASON") == 0) { if (ci->suspendinfo) { s = next_token(NULL); if (!s) { fprintf(stderr, "%s:%d: Corrupt FREASON line," " ignoring\n", fname, line); } else { free(ci->suspendinfo->reason); ci->suspendinfo->reason = sstrdup(s); } } } else if (stricmp(s, "FTIME") == 0) { if (ci->suspendinfo) { long t; #ifdef CLEAN_COMPILE t = 0; #endif s = next_token(NULL); if (s) t = strtol(s, &s, 10); if (!s || *s) { fprintf(stderr, "%s:%d: Corrupt FTIME line," " ignoring\n", fname, line); } else { ci->suspendinfo->suspended = (time_t)t; } } } else { static int warnings = 0; switch (warnings) { case 5: fprintf(stderr, "%s:%d: More unrecognized channel" " options follow\n", fname, line); warnings = -1; /* fall through */ case -1: break; default: fprintf(stderr, "%s:%d: Unrecognized channel option" " `%s'\n", fname, line, s); warnings++; break; } } } /* channel parameters */ } /* while (fgets()) */ if (ci) add_channelinfo(ci); fclose(f); } /*************************************************************************/ static void hyb_load_memo(const char *sourcedir) { FILE *f; char fname[PATH_MAX+1]; char buf[4096]; /* HybServ uses MAXLINE (510); let's be safe */ char *s; MemoInfo *mi = NULL; int line; snprintf(fname, sizeof(fname), "%s/memo.db", sourcedir); f = fopen(fname, "r"); if (!f) { fprintf(stderr, "Cannot open %s: %s\n", fname, strerror(errno)); exit(1); } line = 0; while (fgets(buf, sizeof(buf), f)) { line++; if (!(s = next_token(buf))) continue; if (*s == ';') continue; if (strncmp(s, "->", 2) != 0) { /* New nickname */ NickInfo *ni; NickGroupInfo *ngi; mi = NULL; if (!(ni = get_nickinfo(s))) { fprintf(stderr, "%s:%d: Nickname `%s' not registered," " skipping memos\n", fname, line, s); } else if (ni->status & NS_VERBOTEN) { fprintf(stderr, "%s:%d: Nickname `%s' is forbidden," " skipping memos\n", fname, line, s); } else if (!(ngi = get_nickgroupinfo(ni->nickgroup))) { fprintf(stderr, "%s:%d: BUG: Nickname `%s' missing" "nickgroup, skipping memos\n", fname, line, s); } else { mi = &ngi->memos; } } else if (mi) { /* Memo list contents */ s += 2; if (stricmp(s, "TEXT") == 0) { char *sender = next_token(NULL); char *time_s = next_token(NULL); char *flags_s = next_token(NULL); char *text = next_token(NULL); long time, flags; #ifdef CLEAN_COMPILE time = flags = 0; #endif if (time_s) time = strtol(time_s, &time_s, 10); if (flags_s) flags = strtol(flags_s, &flags_s, 10); if (!sender || !time_s || *time_s || !flags_s || *flags_s || !text) { fprintf(stderr, "%s:%d: Corrupt TEXT line, ignoring\n", fname, line); } else { Memo *m; ARRAY_EXTEND(mi->memos); m = &mi->memos[mi->memos_count-1]; m->number = mi->memos_count; m->flags = (flags & 1) ? 0 : MF_UNREAD; m->time = (time_t)time; strscpy(m->sender, sender, sizeof(m->sender)); m->text = sstrdup(text); } } else { static int warnings = 0; switch (warnings) { case 5: fprintf(stderr, "%s:%d: More unrecognized channel" " options follow\n", fname, line); warnings = -1; /* fall through */ case -1: break; default: fprintf(stderr, "%s:%d: Unrecognized channel option" " `%s'\n", fname, line, s); warnings++; break; } } } /* channel parameters */ } /* while (fgets()) */ fclose(f); } /*************************************************************************/ /*************************************************************************/ static const char *check_hybserv(const char *sourcedir) { static char buf[PATH_MAX+1]; FILE *f; snprintf(buf, sizeof(buf), "%s/nick.db", sourcedir); f = fopen(buf, "r"); if (f) { char *s; fgets(buf, sizeof(buf), f); fclose(f); if (strncmp(buf, "; HybServ", 9) == 0) { s = strchr(buf+10, ' '); if (s) *s = 0; return buf+2; } } return NULL; } static void load_hybserv(const char *sourcedir, int verbose, int ac, char **av) { int i; crypted_passwords = 0; for (i = 1; i < ac; i++) { if (strcmp(av[i],"-crypt") == 0) { crypted_passwords = 1; } else { fprintf(stderr, "Unrecognized option %s\n", av[i]); usage(av[0]); } } #ifndef SERVICES_5_1 if (crypted_passwords) { fprintf(stderr, "Sorry, encrypted passwords are not yet supported.\n"); fprintf(stderr, "Please wait for IRC Services 5.1.\n"); } #endif if (verbose) fprintf(stderr, "Loading nick.db...\n"); hyb_load_nick(sourcedir); if (verbose) fprintf(stderr, "Loading chan.db...\n"); hyb_load_chan(sourcedir); if (verbose) fprintf(stderr, "Loading memo.db...\n"); hyb_load_memo(sourcedir); } /*************************************************************************/ /*************************************************************************/ DBTypeInfo dbtype_hybserv = { "hybserv", check_hybserv, load_hybserv }; /*************************************************************************/