#include #include #include #include #include #include #include #include #include #include "gemlog.h" static struct gemlog_entry **gemlog_readdir_root(struct gemlog_entry **, struct tm, const char *); static struct gemlog_entry **gemlog_readdir_year(struct gemlog_entry **, struct tm, const char *); static struct gemlog_entry **gemlog_readdir_month(struct gemlog_entry **, struct tm, const char *); static struct gemlog_entry **gemlog_readdir_day(struct gemlog_entry **, struct tm, const char *); static struct gemlog_entry **gemlog_readdir_num(struct gemlog_entry **, struct tm, const char *); static struct gemlog_entry ** gemlog_entry_list_append(struct gemlog_entry **list, struct gemlog_entry *item) { int nitems; struct gemlog_entry **ret; if (list == NULL) { nitems = 2; } else { for (nitems = 0; list[nitems] != NULL; nitems++); /* watch out */ nitems += 2; /* one for new item, one for terminating NULL */ } ret = realloc(list, nitems*sizeof(*list)); if (ret == NULL) return NULL; ret[nitems-1] = NULL; ret[nitems-2] = item; return ret; } static struct gemlog_entry ** gemlog_readdir_root(struct gemlog_entry **feed, struct tm timestamp, const char *path) { DIR *directory; struct gemlog_entry **ret; struct dirent *dirlist; char pathbuf[PATH_MAX+1]; directory = opendir(path); if (directory == NULL) return NULL; dirlist = readdir(directory); while (dirlist != NULL) { if (strcmp(dirlist->d_name, ".") == 0 || strcmp(dirlist->d_name, "..") == 0) { dirlist = readdir(directory); continue; } /* because tm_year adds 1900 */ timestamp.tm_year = ((int)strtol(dirlist->d_name, NULL, 10)) - 1900; strlcpy(pathbuf, path, sizeof(pathbuf)); strlcat(pathbuf, "/", sizeof(pathbuf)); strlcat(pathbuf, dirlist->d_name, sizeof(pathbuf)); ret = gemlog_readdir_year(feed, timestamp, pathbuf); if (ret == NULL) { gemlog_entry_list_free(feed); closedir(directory); return NULL; } feed = ret; dirlist = readdir(directory); } closedir(directory); return ret; } static struct gemlog_entry ** gemlog_readdir_year(struct gemlog_entry **feed, struct tm timestamp, const char *path) { DIR *directory; struct gemlog_entry **ret; struct dirent *dirlist; char pathbuf[PATH_MAX+1]; directory = opendir(path); if (directory == NULL) return NULL; dirlist = readdir(directory); while (dirlist != NULL) { if (strcmp(dirlist->d_name, ".") == 0 || strcmp(dirlist->d_name, "..") == 0) { dirlist = readdir(directory); continue; } timestamp.tm_mon = (int)strtol(dirlist->d_name, NULL, 10); timestamp.tm_mon--; /* Month is range (0-11) */ strlcpy(pathbuf, path, sizeof(pathbuf)); strlcat(pathbuf, "/", sizeof(pathbuf)); strlcat(pathbuf, dirlist->d_name, sizeof(pathbuf)); ret = gemlog_readdir_month(feed, timestamp, pathbuf); if (ret == NULL) { closedir(directory); return NULL; } feed = ret; dirlist = readdir(directory); } closedir(directory); return ret; } static struct gemlog_entry ** gemlog_readdir_month(struct gemlog_entry **feed, struct tm timestamp, const char *path) { DIR *directory; struct gemlog_entry **ret; struct dirent *dirlist; char pathbuf[PATH_MAX+1]; directory = opendir(path); if (directory == NULL) return NULL; dirlist = readdir(directory); while (dirlist != NULL) { if (strcmp(dirlist->d_name, ".") == 0 || strcmp(dirlist->d_name, "..") == 0) { dirlist = readdir(directory); continue; } timestamp.tm_mday = (int)strtol(dirlist->d_name, NULL, 10); strlcpy(pathbuf, path, sizeof(pathbuf)); strlcat(pathbuf, "/", sizeof(pathbuf)); strlcat(pathbuf, dirlist->d_name, sizeof(pathbuf)); ret = gemlog_readdir_day(feed, timestamp, pathbuf); if (ret == NULL) { closedir(directory); return NULL; } feed = ret; dirlist = readdir(directory); } closedir(directory); return ret; } static struct gemlog_entry ** gemlog_readdir_day(struct gemlog_entry **feed, struct tm timestamp, const char *path) { DIR *directory; struct gemlog_entry **ret; struct dirent *dirlist; char pathbuf[PATH_MAX+1]; directory = opendir(path); if (directory == NULL) return NULL; dirlist = readdir(directory); while (dirlist != NULL) { if (strcmp(dirlist->d_name, ".") == 0 || strcmp(dirlist->d_name, "..") == 0) { dirlist = readdir(directory); continue; } /* hour is set, but not used, it is just a counter for how * many entries are made within one day */ timestamp.tm_hour = (int)strtol(dirlist->d_name, NULL, 10); strlcpy(pathbuf, path, sizeof(pathbuf)); strlcat(pathbuf, "/", sizeof(pathbuf)); strlcat(pathbuf, dirlist->d_name, sizeof(pathbuf)); ret = gemlog_readdir_num(feed, timestamp, pathbuf); if (ret == NULL) { closedir(directory); return NULL; } feed = ret; dirlist = readdir(directory); } closedir(directory); return ret; } static struct gemlog_entry ** gemlog_readdir_num(struct gemlog_entry **feed, struct tm timestamp, const char *path) { int fd; DIR *directory; struct gemlog_entry **ret; struct gemlog_entry *entry; struct dirent *dirlist; struct stat fst; char pathbuf[PATH_MAX+1]; directory = opendir(path); if (directory == NULL) return NULL; entry = malloc(sizeof(*entry)); if (entry == NULL) { closedir(directory); return NULL; } memset(entry, 0, sizeof(*entry)); entry->date = timestamp; dirlist = readdir(directory); while (dirlist != NULL) { if (strcmp(dirlist->d_name, ".") == 0 || strcmp(dirlist->d_name, "..") == 0) { dirlist = readdir(directory); continue; } if (strcmp(dirlist->d_name, GEMLOG_TITLE_FILENAME) == 0) { strlcpy(pathbuf, path, sizeof(pathbuf)); strlcat(pathbuf, "/", sizeof(pathbuf)); strlcat(pathbuf, dirlist->d_name, sizeof(pathbuf)); fd = open(pathbuf, O_RDONLY); if (fd == -1) { gemlog_entry_free(entry); closedir(directory); return NULL; } if (fstat(fd, &fst) == -1) { gemlog_entry_free(entry); close(fd); closedir(directory); return NULL; } entry->title = malloc(fst.st_size+1); if (entry->title == NULL) { gemlog_entry_free(entry); close(fd); closedir(directory); return NULL; } memset(entry->title, 0, fst.st_size+1); if (read(fd, entry->title, fst.st_size) == -1) { gemlog_entry_free(entry); close(fd); closedir(directory); return NULL; } close(fd); } if (strcmp(dirlist->d_name, GEMLOG_CONTENT_FILENAME) == 0) { strlcpy(pathbuf, path, sizeof(pathbuf)); strlcat(pathbuf, "/", sizeof(pathbuf)); strlcat(pathbuf, dirlist->d_name, sizeof(pathbuf)); entry->content = gemtext_list_decode_file(pathbuf); if (entry->content == NULL) { gemlog_entry_free(entry); closedir(directory); return NULL; } } dirlist = readdir(directory); } ret = gemlog_entry_list_append(feed, entry); if (ret == NULL) { gemlog_entry_free(entry); closedir(directory); return NULL; } closedir(directory); return ret; } struct gemlog_entry ** gemlog_readdir(const char *path) { struct tm timestamp; struct gemlog_entry **ret; memset(×tamp, 0, sizeof(timestamp)); ret = gemlog_readdir_root(NULL, timestamp, path); if (ret == NULL) return NULL; return ret; }