/* Conversion routines for HybServ.
*
* IRC Services is copyright (c) 1996-2007 Andrew Church.
* E-mail: <achurch@achurch.org>
* 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>",
"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, "<unknown>",
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, "<unknown>",
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
};
/*************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1