#include #include #include #include #include #include #include #include #include #include "common.c" /* Feed info. */ struct feed { char *name; /* feed name */ unsigned long new; /* amount of new items per feed */ unsigned long total; /* total items */ struct feed *next; /* linked list */ }; static int showsidebar = 1; /* show sidebar ? */ void /* print error message to stderr */ die(const char *s) { fputs("sfeed_html: ", stderr); fputs(s, stderr); fputc('\n', stderr); exit(EXIT_FAILURE); } struct feed * feednew(void) { struct feed *f; if(!(f = calloc(1, sizeof(struct feed)))) die("can't allocate enough memory"); return f; } void feedsfree(struct feed *f) { struct feed *next; while(f) { next = f->next; free(f->name); free(f); f = next; } } /* print text, ignore tabs, newline and carriage return etc * print some HTML 2.0 / XML 1.0 as normal text */ void print_content_test(const char *s, FILE *fp) { const char *p; int len = 0; for(p = s; *p; p++) { if(*p == '\\') { p++; if(*p == '\\') fputc('\\', fp); else if(*p == 't' && len) fputc('\t', fp); else if(*p == 'n' && len) fputc('\n', fp); } else { fputc(*p, fp); len++; } } } /* print feed name for id; spaces and tabs in string as "-" (spaces in anchors are not valid). */ void printfeednameid(const char *s, FILE *fp) { for(; *s; s++) fputc(isspace((int)*s) ? '-' : *s, fp); } void printhtmlencoded(const char *s, FILE *fp) { for(; *s; s++) { switch(*s) { case '<': fputs("<", fp); break; case '>': fputs(">", fp); break; /* case '&': fputs("&", fp); break;*/ default: fputc(*s, fp); } } } void makepathname(char *buffer, size_t bufsiz, const char *path) { const char *p = path; size_t i = 0, r = 0; /*for(p = path; isspace((int)*p); p++);*/ /* remove leading whitespace */ for(; *p && i < bufsiz; p++) { if(isalpha((int)*p) || isdigit((int)*p)) { buffer[i++] = tolower((int)*p); r = 0; } else { if(!r) { /* dont repeat '-'. */ buffer[i++] = '-'; } r++; } } buffer[i] = '\0'; /* remove trailing - */ for(; i > 0 && (buffer[i] == '-' || buffer[i] == '\0'); i--) buffer[i] = '\0'; } int fileexists(const char *path) { return (!access(path, F_OK)); } int main(int argc, char **argv) { char *line = NULL, *fields[FieldLast]; unsigned long totalfeeds = 0, totalnew = 0; unsigned int islink, isnew; struct feed *feedcurrent = NULL, *feeds = NULL; /* start of feeds linked-list. */ time_t parsedtime, comparetime; size_t size = 0; char name[256]; char dirpath[256]; char filepath[1024]; char reldirpath[1024]; char relfilepath[1024]; FILE *fpindex, *fpitems, *fpmenu, *fpcontent; char feedname[1024]; char *basepath = "feeds"; struct utimbuf contenttime = { 0 }; /* TODO: write menu to file */ /* TODO: write items to file */ /* TODO: write items per category to file? */ if(argc > 1 && argv[1][0] != '\0') basepath = argv[1]; /* tzset();*/ comparetime = time(NULL) - (3600 * 24); /* 1 day is old news */ mkdir(basepath, S_IRWXU); /* write main index page */ snprintf(dirpath, sizeof(dirpath) - 1, "%s/index.html", basepath); if((fpindex = fopen(dirpath, "w+b"))) { } snprintf(dirpath, sizeof(dirpath) - 1, "%s/menu.html", basepath); if(!(fpmenu = fopen(dirpath, "w+b"))) { /* TODO: error */ fclose(fpindex); return EXIT_FAILURE; } snprintf(dirpath, sizeof(dirpath) - 1, "%s/items.html", basepath); if(!(fpitems = fopen(dirpath, "w+b"))) { /* TODO: error */ fclose(fpmenu); fclose(fpindex); return EXIT_FAILURE; } feedname[0] = '\0'; while(parseline(&line, &size, fields, FieldLast, stdin, FieldSeparator) > 0) { dirpath[0] = '\0'; filepath[0] = '\0'; reldirpath[0] = '\0'; relfilepath[0] = '\0'; makepathname(name, sizeof(name) - 1, fields[FieldFeedName]); if(name[0] != '\0') { snprintf(dirpath, sizeof(dirpath) - 1, "%s/%s", basepath, name); /* TODO: handle error. */ if(mkdir(dirpath, S_IRWXU) != -1) { } /* snprintf(reldirpath, sizeof(reldirpath) - 1, "%s", name);*/ strncpy(reldirpath, name, sizeof(reldirpath) - 1); makepathname(name, sizeof(name), fields[FieldTitle]); if(name[0] != '\0') { snprintf(filepath, sizeof(filepath) - 1, "%s/%s.html", dirpath, name); snprintf(relfilepath, sizeof(relfilepath) - 1, "%s/%s.html", reldirpath, name); /* TODO: if file exists, dont overwrite. */ /* TODO: give file title and timestamp of article, touch() ?. */ if(!fileexists(filepath) && (fpcontent = fopen(filepath, "w+b"))) { fputs("", fpcontent); fputs("

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

", fpcontent); print_content_test(fields[FieldContent], fpcontent); fputs("", fpcontent); fclose(fpcontent); } /* first of feed section or new feed section. */ if(!totalfeeds || strcmp(feedcurrent->name, fields[FieldFeedName])) { if(totalfeeds) { /* end previous one. */ fputs("\n", fpitems); if(!(feedcurrent->next = calloc(1, sizeof(struct feed)))) die("can't allocate enough memory"); feedcurrent = feedcurrent->next; } else { if(!(feedcurrent = calloc(1, sizeof(struct feed)))) die("can't allocate enough memory"); feeds = feedcurrent; /* first item. */ if(fields[FieldFeedName][0] == '\0') { fputs("-nosidebar", fpitems); /* set other id on div if no sidebar for styling */ showsidebar = 0; } } /* write menu link if new. */ if(!(feedcurrent->name = xstrdup(fields[FieldFeedName]))) die("can't allocate enough memory"); if(fields[FieldFeedName][0] != '\0') { fputs("

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

\n", fpitems); } fputs("", fpitems); totalfeeds++; } /* write item. */ parsedtime = (time_t)strtol(fields[FieldUnixTimestamp], NULL, 10); /* set modified and access time of file to time of item. */ contenttime.actime = parsedtime; contenttime.modtime = parsedtime; utime(filepath, &contenttime); isnew = (parsedtime >= comparetime); islink = (strlen(fields[FieldLink]) > 0); totalnew += isnew; feedcurrent->new += isnew; feedcurrent->total++; 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("\t\t\n", fpitems); /* div items */ } if(showsidebar) { /* fputs("\t\t
\n\t\t\t\n\t\t
\n", fpmenu);*/ } fputs("" "" " " " Newsfeeds (", fpindex); fprintf(fpindex, "%lu", totalnew); fputs(")" " " " " " " " " " " " " " " " " "", fpindex); fclose(fpmenu); fclose(fpitems); fclose(fpindex); free(line); /* free line */ feedsfree(feeds); /* free feeds linked-list */ return EXIT_SUCCESS; }