#include #include #include #include #include #include #include #include #include #include #include #include #include #include "queue.h" #include "util.h" static int showsidebar = 1; /* show sidebar ? */ static FILE *fpindex = NULL, *fpitems = NULL, *fpmenu = NULL; static FILE *fpcontent = NULL; static char *line = NULL; static SLIST_HEAD(fhead, feed) fhead = SLIST_HEAD_INITIALIZER(fhead); static struct utimbuf contenttime; static void cleanup(void) { if(fpmenu) fclose(fpmenu); if(fpitems) fclose(fpitems); if(fpindex) fclose(fpindex); if(fpcontent) fclose(fpcontent); fpmenu = NULL; fpitems = NULL; fpindex = NULL; fpcontent = NULL; } /* same as err() but first call cleanup() function */ static void xerr(int eval, const char *fmt, ...) { int saved_errno = errno; va_list ap; cleanup(); errno = saved_errno; va_start(ap, fmt); verr(eval, fmt, ap); va_end(ap); } static int esnprintf(char *str, size_t size, const char *fmt, ...) { va_list ap; int r; va_start(ap, fmt); r = vsnprintf(str, size, fmt, ap); va_end(ap); if(r == -1 || (size_t)r >= size) xerr(1, "snprintf"); return r; } /* print text, ignore tabs, newline and carriage return etc * print some HTML 2.0 / XML 1.0 as normal text */ static void printcontent(const char *s, FILE *fp) { const char *p; for(p = s; *p; p++) { if(*p == '\\') { p++; if(*p == '\\') fputc('\\', fp); else if(*p == 't') fputc('\t', fp); else if(*p == 'n') fputc('\n', fp); else fputc(*p, fp); /* unknown */ } else { fputc(*p, fp); } } } /* TODO: bufsiz - 1 ? */ static size_t makepathname(const char *path, char *buffer, size_t bufsiz) { size_t i = 0, r = 0; for(; *path && i < bufsiz - 1; path++) { if(isalpha((int)*path) || isdigit((int)*path)) { buffer[i++] = tolower((int)*path); r = 0; } else { if(!r) /* don't repeat '-'. */ buffer[i++] = '-'; r++; } } buffer[i] = '\0'; /* remove trailing - */ for(; i > 0 && (buffer[i] == '-' || buffer[i] == '\0'); i--) buffer[i] = '\0'; return i; } int main(int argc, char *argv[]) { struct feed *f, *fcur = NULL; char *fields[FieldLast]; char name[64]; /* TODO: bigger size? */ char dirpath[PATH_MAX], filepath[PATH_MAX]; char reldirpath[PATH_MAX], relfilepath[PATH_MAX]; char *feedname = "", *basepath = "."; unsigned long totalfeeds = 0, totalnew = 0; unsigned int isnew; time_t parsedtime, comparetime; size_t linesize = 0, namelen, basepathlen; struct stat st; struct utimbuf contenttime; int r; memset(&contenttime, 0, sizeof(contenttime)); if(argc > 1 && argv[1][0] != '\0') basepath = argv[1]; comparetime = time(NULL) - (3600 * 24); /* 1 day is old news */ basepathlen = strlen(basepath); if(basepathlen > 0) mkdir(basepath, S_IRWXU); /* write main index page */ esnprintf(dirpath, sizeof(dirpath), "%s/index.html", basepath); if(!(fpindex = fopen(dirpath, "w+b"))) xerr(1, "fopen"); esnprintf(dirpath, sizeof(dirpath), "%s/menu.html", basepath); if(!(fpmenu = fopen(dirpath, "w+b"))) xerr(1, "fopen"); esnprintf(dirpath, sizeof(dirpath), "%s/items.html", basepath); if(!(fpitems = fopen(dirpath, "w+b"))) xerr(1, "fopen"); fputs("" "" "
", fpitems); if(!(fcur = calloc(1, sizeof(struct feed)))) xerr(1, "calloc"); SLIST_INSERT_HEAD(&fhead, fcur, entry); while(parseline(&line, &linesize, fields, FieldLast, '\t', stdin) > 0) { feedname = fields[FieldFeedName]; if(feedname[0] == '\0') { feedname = "unknown"; /* assume single feed (hide sidebar) */ if(!totalfeeds) showsidebar = 0; } /* first of feed section or new feed section (differ from previous). */ if(!totalfeeds || strcmp(fcur->name, feedname)) { /* TODO: * - makepathname isn't necesary if fields[FieldFeedName] * is the same as the previous line. * - move this part below where FieldFeedName is * checked if it's different ? */ /* make directory for feedname */ if(!(namelen = makepathname(feedname, name, sizeof(name)))) continue; esnprintf(dirpath, sizeof(dirpath), "%s/%s", basepath, name); /* directory doesn't exist: try to create it. */ if(stat(dirpath, &st) == -1 && mkdir(dirpath, S_IRWXU) == -1) xerr(1, "sfeed_frames: can't make directory '%s'", dirpath); strlcpy(reldirpath, name, sizeof(reldirpath)); /* TODO: check truncation */ if(!(f = calloc(1, sizeof(struct feed)))) xerr(1, "calloc"); if(!(f->name = strdup(feedname))) xerr(1, "strdup"); SLIST_INSERT_AFTER(fcur, f, entry); fcur = f; /* end previous one. */ if(totalfeeds) { fputs("\n", fpitems); } /* write menu link if new. */ if(fields[FieldFeedName][0] != '\0') { fputs("

name, fpitems); fputs("\">name, fpitems); fputs("\">", fpitems); fputs(fcur->name, fpitems); fputs("

\n", fpitems); } fputs("\n", fpitems); totalfeeds++; } /* write content */ if(!(namelen = makepathname(fields[FieldTitle], name, sizeof(name)))) continue; esnprintf(filepath, sizeof(filepath), "%s/%s.html", dirpath, name); esnprintf(relfilepath, sizeof(relfilepath), "%s/%s.html", reldirpath, name); /* file doesn't exist yet and has write access */ if(access(filepath, F_OK) != 0) { if(!(fpcontent = fopen(filepath, "w+b"))) xerr(1, "fopen"); fputs("" "\n" "
" "

", fpcontent); printhtmlencoded(fields[FieldTitle], fpcontent); fputs("

", fpcontent); printcontent(fields[FieldContent], fpcontent); fputs("
", fpcontent); fclose(fpcontent); fpcontent = NULL; } /* write item. */ r = strtotime(fields[FieldUnixTimestamp], &parsedtime); /* set modified and access time of file to time of item. */ if(r != -1) { contenttime.actime = parsedtime; contenttime.modtime = parsedtime; utime(filepath, &contenttime); } isnew = (r != -1 && parsedtime >= comparetime) ? 1 : 0; totalnew += isnew; fcur->totalnew += isnew; fcur->total++; if(isnew) fputs("", fpitems); else fputs("", fpitems); fputs("\n", fpitems); } if(totalfeeds) { fputs("
", fpitems); fputs(fields[FieldTimeFormatted], fpitems); fputs("", fpitems); if(isnew) fputs("", fpitems); fputs("", fpitems); printhtmlencoded(fields[FieldTitle], fpitems); fputs("", fpitems); if(isnew) fputs("", fpitems); fputs("
\n", fpitems); } fputs("\n
\n", fpitems); /* div items */ if(showsidebar) { fputs("" "\n" "\n" "
", fpmenu); SLIST_FOREACH(f, &fhead, entry) { if(!f->name || f->name[0] == '\0') continue; if(f->totalnew) fputs("name, fpmenu); fputs("\" target=\"items\">", fpmenu); if(f->totalnew > 0) fputs("", fpmenu); fprintf(fpmenu, "%s (%lu)", f->name, f->totalnew); if(f->totalnew > 0) fputs("", fpmenu); fputs("
\n", fpmenu); } fputs("
", fpmenu); } fputs("\n\tNewsfeed (", fpindex); fprintf(fpindex, "%lu", totalnew); fputs(")\n\t\n" "\n" "\n", fpindex); if(showsidebar) { fputs("\n" " \n", fpindex); } else { fputs("\n", fpindex); } fputs("\t\n" "\t\t\n" "\t\t\n" "\t\n" "\n" "", fpindex); cleanup(); return 0; }