#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include "macros.h"
#include "xmalloc.h"
#include "imclient.h"
#include "imparse.h"
#include "wildmat.h"
#define NUM_STORAGE_CLASSES 100
#define BOOL int
#define FALSE (0)
#define TRUE (1)
#define STATIC static
typedef struct _NEWSGROUP {
char *Name;
char *Rest;
unsigned long Last;
unsigned long Lastpurged;
time_t Keep;
time_t Default;
time_t Purge;
BOOL Poison;
} NEWSGROUP;
typedef struct _EXPIRECLASS {
time_t Keep;
time_t Default;
time_t Purge;
BOOL Missing;
BOOL ReportedMissing;
} EXPIRECLASS;
#define MAGIC_TIME 49710.
STATIC NEWSGROUP EXPdefault;
STATIC int nGroups;
STATIC int nGroups_alloc;
STATIC time_t EXPremember;
STATIC time_t Now;
STATIC EXPIRECLASS EXPclasses[NUM_STORAGE_CLASSES];
STATIC NEWSGROUP *Groups;
STATIC int EXPverbose;
STATIC int EXPsplit(char *p, char sep, char **argv, int count)
{
int i;
if (!p)
return 0;
while (*p == sep)
++p;
if (!*p)
return 0;
if (!p)
return 0;
while (*p == sep)
++p;
if (!*p)
return 0;
for (i = 1, *argv++ = p; *p; )
if (*p++ == sep) {
p[-1] = '\0';
for (; *p == sep; p++);
if (!*p)
return i;
if (++i == count)
return -1;
*argv++ = p;
}
return i;
}
STATIC BOOL EXPgetnum(int line, char *word, time_t *v, char *name)
{
char *p;
BOOL SawDot;
double d;
if (caseEQ(word, "never")) {
*v = (time_t)0;
return TRUE;
}
for (p = word; ISWHITE(*p); p++)
continue;
if (*p == '+' || *p == '-')
p++;
for (SawDot = FALSE; *p; p++)
if (*p == '.') {
if (SawDot)
break;
SawDot = TRUE;
}
else if (!isdigit( (int)*p))
break;
if (*p) {
(void)fprintf(stderr, "Line %d, bad `%c' character in %s field\n",
line, *p, name);
return FALSE;
}
d = atof(word);
if (d > MAGIC_TIME)
*v = (time_t)0;
else
*v = Now - (time_t)(d * 86400.);
return TRUE;
}
STATIC void EXPmatch(char *p, NEWSGROUP *v, char mod)
{
NEWSGROUP *ngp;
int i;
BOOL negate;
negate = *p == '!';
if (negate)
p++;
for (ngp = Groups, i = nGroups; --i >= 0; ngp++)
{
if (negate ? !wildmat(ngp->Name, p) : wildmat(ngp->Name, p))
if (mod == 'a') {
ngp->Keep = v->Keep;
ngp->Default = v->Default;
ngp->Purge = v->Purge;
ngp->Poison = v->Poison;
if (EXPverbose > 4) {
(void)printf("%s", ngp->Name);
(void)printf(" %13.13s", ctime(&v->Keep) + 3);
(void)printf(" %13.13s", ctime(&v->Default) + 3);
(void)printf(" %13.13s", ctime(&v->Purge) + 3);
(void)printf(" (%s)\n", p);
}
}
}
}
BOOL EXPreadfile(FILE *F)
{
char *p;
int i;
int j;
int k;
char mod;
NEWSGROUP v;
BOOL SawDefault;
char buff[BUFSIZ];
char *fields[7];
char **patterns;
EXPremember = -1;
SawDefault = FALSE;
patterns = NEW(char*, nGroups);
for (i = 0; i < NUM_STORAGE_CLASSES; i++)
EXPclasses[i].ReportedMissing = EXPclasses[i].Missing = TRUE;
for (i = 1; fgets(buff, sizeof buff, F) != NULL; i++) {
if ((p = strchr(buff, '\n')) == NULL) {
(void)fprintf(stderr, "Line %d too long\n", i);
return FALSE;
}
*p = '\0';
p = strchr(buff, '#');
if (p)
*p = '\0';
else
p = buff + strlen(buff);
while (--p >= buff) {
if (isspace((int)*p))
*p = '\0';
else
break;
}
if (buff[0] == '\0')
continue;
if ((j = EXPsplit(buff, ':', fields, SIZEOF(fields))) == -1) {
(void)fprintf(stderr, "Line %d too many fields\n", i);
return FALSE;
}
if (EQ(fields[0], "/remember/")) {
if (j != 2) {
(void)fprintf(stderr, "Line %d bad format\n", i);
return FALSE;
}
if (EXPremember != -1) {
(void)fprintf(stderr, "Line %d duplicate /remember/\n", i);
return FALSE;
}
if (!EXPgetnum(i, fields[1], &EXPremember, "remember"))
return FALSE;
continue;
}
if (j == 4) {
j = atoi(fields[0]);
if ((j < 0) || (j > NUM_STORAGE_CLASSES)) {
fprintf(stderr, "Line %d bad storage class %d\n", i, j);
}
if (!EXPgetnum(i, fields[1], &EXPclasses[j].Keep, "keep")
|| !EXPgetnum(i, fields[2], &EXPclasses[j].Default, "default")
|| !EXPgetnum(i, fields[3], &EXPclasses[j].Purge, "purge"))
return FALSE;
if (EXPclasses[j].Purge) {
if (EXPclasses[j].Keep && EXPclasses[j].Keep < EXPclasses[j].Purge) {
(void)fprintf(stderr, "Line %d keep>purge\n", i);
return FALSE;
}
if (EXPclasses[j].Default && EXPclasses[j].Default < EXPclasses[j].Purge) {
(void)fprintf(stderr, "Line %d default>purge\n", i);
return FALSE;
}
}
EXPclasses[j].Missing = FALSE;
continue;
}
if (j != 5) {
(void)fprintf(stderr, "Line %d bad format\n", i);
return FALSE;
}
if (strchr(fields[1], 'M') != NULL)
mod = 'm';
else if (strchr(fields[1], 'U') != NULL)
mod = 'u';
else if (strchr(fields[1], 'A') != NULL)
mod = 'a';
else {
(void)fprintf(stderr, "Line %d bad modflag\n", i);
return FALSE;
}
v.Poison = (strchr(fields[1], 'X') != NULL);
if (!EXPgetnum(i, fields[2], &v.Keep, "keep")
|| !EXPgetnum(i, fields[3], &v.Default, "default")
|| !EXPgetnum(i, fields[4], &v.Purge, "purge"))
return FALSE;
if (v.Purge) {
if (v.Keep && v.Keep < v.Purge) {
(void)fprintf(stderr, "Line %d keep>purge\n", i);
return FALSE;
}
if (v.Default && v.Default < v.Purge) {
(void)fprintf(stderr, "Line %d default>purge\n", i);
return FALSE;
}
}
if (fields[0][0] == '*' && fields[0][1] == '\0' && mod == 'a') {
if (SawDefault) {
(void)fprintf(stderr, "Line %d duplicate default\n", i);
return FALSE;
}
EXPdefault.Keep = v.Keep;
EXPdefault.Default = v.Default;
EXPdefault.Purge = v.Purge;
EXPdefault.Poison = v.Poison;
SawDefault = TRUE;
}
if ((j = EXPsplit(fields[0], ',', patterns, nGroups)) == -1) {
(void)fprintf(stderr, "Line %d too many patterns\n", i);
return FALSE;
}
for (k = 0; k < j; k++)
EXPmatch(patterns[k], &v, mod);
}
DISPOSE(patterns);
return TRUE;
}
int ExpireExists(int num)
{
if ((num<0) || (num>=nGroups))
return 1;
return 0;
}
time_t GetExpireTime(int num)
{
return Groups[num].Default;
}
char *GetExpireName(int num)
{
return Groups[num].Name;
}
int readconfig_init(void)
{
Now = time(NULL);
nGroups = 0;
nGroups_alloc = 1000;
Groups=(NEWSGROUP *) malloc(sizeof(NEWSGROUP) * 1000);
if (Groups==NULL) fatal("Unable to alloc",0);
return 0;
}
void artificial_matchall(int days)
{
NEWSGROUP ne;
ne.Default = Now - (time_t)(days * 86400.);
EXPmatch("*", &ne,'a');
}
#if 0
void show_groups(void)
{
int lup;
for (lup=0;lup<nGroups;lup++)
{
printf("name = %s\n",Groups[lup].Name);
printf("expires = %uld\n",Groups[lup].Keep);
printf("expires = %uld\n",Groups[lup].Default);
printf("expires = %uld\n",Groups[lup].Purge);
}
}
#endif
void
callback_list(struct imclient *imclient,
void *rock,
struct imclient_reply *reply)
{
char *s, *end;
char *mailbox, *attributes, *separator;
int c;
s = reply->text;
if (*s++ != '(') return;
end = strchr(s, ')');
if (!end) return;
attributes = s;
s = end;
*s++ = '\0';
if (*s++ != ' ') return;
if (*s == 'N') {
if (s[1] != 'I' || s[2] != 'L') return;
separator = "";
s += 3;
}
else if (*s == '\"') {
s++;
if (*s == '\\') s++;
separator = s++;
if (*s != '\"') return;
*s++ = '\0';
}
if (*s++ != ' ') return;
c = imparse_astring(&s, &mailbox);
if (c != '\0') return;
if ((strncasecmp(mailbox,"INBOX",5)!=0) && (strncasecmp(mailbox,"user.",5)!=0))
{
Groups[nGroups].Name = malloc( strlen(mailbox)+1);
strcpy(Groups[nGroups].Name, mailbox);
nGroups++;
if (nGroups >= nGroups_alloc)
{
nGroups_alloc +=1000;
Groups=(NEWSGROUP *) realloc(Groups, sizeof(NEWSGROUP) * nGroups_alloc);
if (Groups==NULL) fatal("Unable to alloc",0);
}
}
for (s = attributes; (end = strchr(s, ' '))!=NULL; s = end+1) {
*s = '\0';
}
}