#include <config.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <syslog.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include "assert.h"
#include "global.h"
#include "xmalloc.h"
#include "exitcodes.h"
#include "imap_err.h"
#include "mailbox.h"
#include "mboxlist.h"
#include "convert_code.h"
extern int optind;
extern char *optarg;
int code = 0;
void do_syncnews(void);
char **group = 0;
int *group_seen;
int group_num = 0;
int group_alloc = 0;
void readactive(char *active);
void usage(void)
{
fprintf(stderr, "usage: syncnews [-C <alt_config>] active\n");
exit(EC_USAGE);
}
int main(int argc, char **argv)
{
int opt;
char *alt_config = NULL;
if (geteuid() == 0) fatal("must run as the Cyrus user", EC_USAGE);
while ((opt = getopt(argc, argv, "C:")) != EOF) {
switch (opt) {
case 'C':
alt_config = optarg;
break;
default:
usage();
}
}
cyrus_init(alt_config, "syncnews", 0);
if (!argv[optind] || argv[optind+1]) usage();
readactive(argv[optind]);
do_syncnews();
cyrus_done();
return code;
}
#define GROUPGROW 300
int compare_group(char **a,char **b)
{
return strcmp(*a, *b);
}
void readactive(char *active)
{
FILE *active_file;
char buf[1024];
char *p;
const char *newsprefix;
int newsprefixlen = 0;
int lineno = 0;
newsprefix = config_getstring("newsprefix", 0);
if (newsprefix) {
newsprefixlen = strlen(newsprefix);
if (newsprefix[newsprefixlen-1] == '.') {
newsprefixlen--;
}
}
active_file = fopen(active, "r");
if (!active_file) {
perror(active);
syslog(LOG_ERR, "cannot read active file %s: %m", active);
cyrus_done();
exit(EC_NOINPUT);
}
while (fgets(buf, sizeof(buf), active_file)) {
lineno++;
p = strchr(buf, ' ');
if (!p) goto badactive;
*p++ = '\0';
p = strchr(p, ' ');
if (!p) goto badactive;
p = strchr(p+1, ' ');
if (!p) goto badactive;
p++;
if (*p == 'y' || *p == 'm' || *p == 'n') {
if (group_num == group_alloc) {
group_alloc += GROUPGROW;
group = (char **) xrealloc((char *)group,
group_alloc * sizeof(char *));
group_seen = (int *) xrealloc((char *)group_seen,
group_alloc * sizeof(int));
}
if (newsprefixlen) {
group[group_num] = xmalloc(strlen(buf)+newsprefixlen+2);
strcpy(group[group_num], newsprefix);
group[group_num][newsprefixlen] = '.';
strcpy(group[group_num]+newsprefixlen+1, buf);
}
else {
group[group_num] = xstrdup(buf);
}
group_seen[group_num] = 0;
group_num++;
}
}
if (ferror(active_file)) {
fprintf(stderr, "syncnews: error reading active file\n");
syslog(LOG_ERR, "error reading active file");
cyrus_done();
exit(EC_DATAERR);
}
fclose(active_file);
if (group_num == 0) {
fprintf(stderr, "syncnews: no groups in active file\n");
syslog(LOG_ERR, "no groups in active file");
cyrus_done();
exit(EC_DATAERR);
}
qsort(group, group_num, sizeof(char *), (int (*)(const void *, const void *)) compare_group);
return;
badactive:
fprintf(stderr, "syncnews: bad line %d in active file\n", lineno);
syslog(LOG_ERR, "bad line %d in active file", lineno);
cyrus_done();
exit(EC_DATAERR);
}
void do_syncnews(void)
{
int r;
int i;
r = mboxlist_syncnews(group_num, group, group_seen);
if (r) {
com_err("syncnews: resynchronizing", r,
(r == IMAP_IOERROR) ? error_message(errno) : NULL);
code = convert_code(r);
return;
}
for (i = 0; i < group_num; i++) {
if (!group_seen[i]) {
r = mboxlist_createmailbox(group[i],
MBTYPE_NETNEWS, "news",
1, "anonymous", NULL, 0, 0, 0);
if (r == IMAP_MAILBOX_BADNAME) {
printf("ignored %s\n", group[i]);
}
else if (r) {
fprintf(stderr, "syncnews: cannot creat %s: %s\n",
group[i], error_message(r));
syslog(LOG_ERR, "cannot create %s: %s",
group[i], error_message(r));
}
else {
printf("created %s\n", group[i]);
}
}
}
return;
}
void fatal(const char* s, int code)
{
fprintf(stderr, "syncnews: %s\n", s);
cyrus_done();
exit(code);
}