src/bencode/encode.c \
src/block.c \
src/default.c \
+ src/feed.c \
src/file.c \
src/fs/concat.c \
src/fs/dir.c \
src/opt/set.c \
src/opt/watch.c \
src/opt/worker.c \
+ src/rss/entry.c \
+ src/rss/footer.c \
+ src/rss/header.c \
+ src/rss/info.c \
src/server/start.c \
src/session.c \
src/setup.c \
inc/bencode.h \
inc/block.h \
inc/default.h \
+ inc/feed.h \
inc/file.h \
inc/fs.h \
inc/hash.h \
inc/log.h \
inc/main.h \
inc/opt.h \
+ inc/rss.h \
inc/server.h \
inc/session.h \
inc/setup.h \
--- /dev/null
+#ifndef __FEED_H_
+#define __FEED_H_
+
+#include<rss.h>
+#include<torrent.h>
+
+#define FEED_DIRECTORY PREFIX "/feeds"
+
+int feed();
+
+#endif
#include<stdlib.h>
#include<add.h>
+#include<feed.h>
#include<init.h>
#include<server.h>
#include<watch.h>
--- /dev/null
+#ifndef __RSS_H_
+#define __RSS_H_
+
+#include<stdio.h>
+#include<string.h>
+#include<time.h>
+
+struct rss_channel_info {
+ char *title;
+ char *link;
+ char *description;
+ char *language;
+ struct tm last_build_date;
+};
+
+struct rss_entry {
+ char *title;
+ char *link;
+ struct tm pub_date;
+ char *description;
+ char *guid;
+};
+
+#define RSS_TAG_CHANNEL_START "<channel>"
+#define RSS_TAG_CHANNEL_END "</channel>"
+#define RSS_TAG_DESCRIPTION_START "<description>"
+#define RSS_TAG_DESCRIPTION_END "</description>"
+#define RSS_TAG_GUID_START "<guid>"
+#define RSS_TAG_GUID_END "</guid>"
+#define RSS_TAG_ITEM_START "<item>"
+#define RSS_TAG_ITEM_END "</item>"
+#define RSS_TAG_LANGUAGE_START "<language>"
+#define RSS_TAG_LANGUAGE_END "</language>"
+#define RSS_TAG_LASTBUILDDATE_START "<lastBuildDate>"
+#define RSS_TAG_LASTBUILDDATE_END "</lastBuildDate>"
+#define RSS_TAG_LINK_START "<link>"
+#define RSS_TAG_LINK_END "</link>"
+#define RSS_TAG_PUBDATE_START "<pubDate>"
+#define RSS_TAG_PUBDATE_END "</pubDate>"
+#define RSS_TAG_RSS_START "<rss version=\"2.0\">"
+#define RSS_TAG_RSS_END "</rss>"
+#define RSS_TAG_TITLE_START "<title>"
+#define RSS_TAG_TITLE_END "</title>"
+
+#define RSS_DEFAULT_CHANNEL_DESCRIPTION ""
+#define RSS_DEFAULT_ENTRY_DESCRIPTION "no description"
+#define RSS_DEFAULT_LANGUAGE "en-us"
+
+int rss_entry(FILE*,struct rss_entry*);
+int rss_footer(FILE*);
+int rss_header(FILE*);
+int rss_info(FILE*,struct rss_channel_info*);
+
+#endif
int watch_fd;
};
+#define TORRENT_FILE_DIRECTORY "/torrents"
+#define TORRENT_FILE_EXTENSION ".torrent"
+
int torrent_add(struct torrent*,struct file*);
int torrent_file(const char*,struct torrent*);
ssize_t torrent_file_info(struct torrent*,uint8_t**);
--- /dev/null
+#include<feed.h>
+
+static int feed_entries(FILE*,struct torrent*);
+static int feed_generate(struct torrent*);
+static char *feed_path(const char*,const char*);
+//static int feed_now(char*,size_t);
+
+int feed() {
+ for(size_t i=0;i<session.torrent_count;i++) {
+ if(feed_generate(session.torrents[i])<0) { return -1; }
+ }
+
+ return 1;
+}
+
+static int feed_generate(struct torrent *torrent) {
+ FILE *fp;
+ char *path;
+ struct rss_channel_info info;
+
+ path = feed_path(PREFIX FEED_DIRECTORY,torrent->name);
+ if(NULL==path) { return -1; }
+
+ fp = fopen(path,"w");
+ if(NULL==fp) {
+ free(path);
+ return -1;
+ }
+
+ if(torrent_file(PREFIX TORRENT_FILE_DIRECTORY,torrent)<0) { goto clean; }
+
+ if(rss_header(fp)<0) { goto clean; }
+ if(rss_info(fp,&info)<0) { goto clean; }
+
+ if(feed_entries(fp,torrent)<0) { goto clean; }
+
+ if(rss_footer(fp)<0) { goto clean; }
+
+ fclose(fp);
+ free(path);
+
+ return 1;
+clean:
+ fclose(fp);
+ remove(path);
+ free(path);
+ return -1;
+}
+
+static int feed_entries(FILE *fp, struct torrent *torrent) {
+ return -1;
+}
+
+static char *feed_path(const char *directory, const char *name) {
+ return NULL;
+}
+
+/*static int feed_now(char *buf,size_t buf_len) {
+ struct tm now;
+
+ now = *localtime(&(time_t){time(NULL)});
+ if(!(strftime((*timebuf),buf_len, "%a, %d %b %Y %H:%M:%S %z", &now))) { return -1; }
+
+ return 1;
+} */
#include<init.h>
+// NOTE: see src/opt/set.c for list of fields/options
+// allowed to be set in config files
+
struct option long_options[] = {
{"config-file", required_argument, 0, 'c'},
{"daemon", no_argument, 0, 'd'},
if(setup_logging()<0) { return EXIT_FAILURE; }
if(add()<0) { return EXIT_FAILURE; }
- //if(feed()<0) { return EXIT_FAILURE; }
+ if(feed()<0) { return EXIT_FAILURE; }
if(watch()<0) { return EXIT_FAILURE; }
while(1) { }
int (*function)(const char*);
};
+// NOTE: see src/init.c for list of CLI options
+
struct option_lookup_table_entry option_lookup_table[] = {
{"file_filter",&opt_set_file_filter},
{"piece_length",&opt_set_piece_length},
}
log_err(OPT_MESSAGE_UNKNOWN_OPTION,key);
- return 0;
+ return -1;
}
--- /dev/null
+#include<rss.h>
+
+static int rss_entry_description(FILE*,const char*);
+static int rss_entry_end(FILE*);
+static int rss_entry_guid(FILE*,const char*);
+static int rss_entry_link(FILE*,const char*);
+static int rss_entry_pubdate(FILE*,const struct tm*);
+static int rss_entry_start(FILE*);
+static int rss_entry_title(FILE*,const char*);
+
+int rss_entry(FILE *fp, struct rss_entry *entry) {
+ if(NULL==fp) { return -1; }
+ if(NULL==entry) { return -1; }
+
+ if(rss_entry_start(fp)<0) { return -1; }
+
+ if(rss_entry_title(fp,entry->title)<0) { return -1; }
+ if(rss_entry_link(fp,entry->link)<0) { return -1; }
+ if(rss_entry_pubdate(fp,&(entry->pub_date))<0) { return -1; }
+ if(rss_entry_description(fp,entry->description)<0) { return -1; }
+ if(rss_entry_guid(fp,entry->guid)<0) { return -1; }
+
+ if(rss_entry_end(fp)<0) { return -1; }
+
+ return -1;
+}
+
+static int rss_entry_description(FILE *fp, const char *description) {
+ size_t len;
+
+ const char start[] = RSS_TAG_DESCRIPTION_START;
+ if(fwrite(start,sizeof(char),sizeof(start)-1,fp)!=sizeof(start)-1) { return -1; }
+
+ if((NULL==description)||(0==strlen(description))) {
+ const char default_description[] = RSS_DEFAULT_ENTRY_DESCRIPTION;
+ if(fwrite(
+ default_description, /* void* ptr */
+ sizeof(char), /* size_t size */
+ sizeof(default_description)-1, /* size_t nmemb */
+ fp /* FILE *stream */
+ )!=sizeof(default_description)-1) { return -1; }
+ } else {
+ len = strlen(description);
+ if(fwrite(description,sizeof(char),len,fp)!=len) { return -1; }
+ }
+
+ const char end[] = RSS_TAG_DESCRIPTION_END;
+ if(fwrite(end,sizeof(char),sizeof(end)-1,fp)!=sizeof(end)-1) { return -1; }
+
+ return -1;
+}
+
+static int rss_entry_end(FILE *fp) {
+ const char end[] = RSS_TAG_ITEM_END;
+ if(fwrite(end,sizeof(char),sizeof(end)-1,fp)!=sizeof(end)-1) { return -1; }
+
+ return 1;
+}
+
+static int rss_entry_guid(FILE *fp, const char *guid) {
+ size_t len;
+
+ if(NULL==guid) { return 1; }
+
+ len = strlen(guid);
+ if(0==len) { return 1; }
+
+ const char start[] = RSS_TAG_GUID_START;
+ if(fwrite(start,sizeof(char),sizeof(start)-1,fp)!=sizeof(start)-1) { return -1; }
+
+ if(fwrite(guid,sizeof(char),len,fp)!=len) { return -1; }
+
+ const char end[] = RSS_TAG_GUID_END;
+ if(fwrite(end,sizeof(char),sizeof(end)-1,fp)!=sizeof(end)-1) { return -1; }
+
+ return 1;
+}
+
+static int rss_entry_link(FILE *fp, const char *link) {
+ size_t len;
+
+ if(NULL==link) { return -1; }
+ len = strlen(link);
+ if(len==0) { return -1; }
+
+ const char start[] = RSS_TAG_LINK_START;
+ if(fwrite(start,sizeof(char),sizeof(start)-1,fp)!=sizeof(start)-1) { return -1; }
+
+ if(fwrite(link,sizeof(char),len,fp)!=len) { return -1; }
+
+ const char end[] = RSS_TAG_TITLE_END;
+ if(fwrite(end,sizeof(char),sizeof(end)-1,fp)!=sizeof(end)-1) { return -1; }
+
+ return 1;
+}
+
+static int rss_entry_pubdate(FILE *fp,const struct tm *date) {
+ char buf[40];
+ size_t buf_size = 40;
+
+ const char start[] = RSS_TAG_PUBDATE_START;
+ if(fwrite(start,sizeof(char),sizeof(start)-1,fp)!=sizeof(start)-1) { return -1; }
+
+ if(!(strftime(buf,buf_size, "%a, %d %b %Y %H:%M:%S %z", date))) { return -1; }
+
+ const char end[] = RSS_TAG_PUBDATE_END;
+ if(fwrite(end,sizeof(char),sizeof(end)-1,fp)!=sizeof(end)-1) { return -1; }
+
+ return 1;
+}
+
+static int rss_entry_start(FILE *fp) {
+ const char start[] = RSS_TAG_ITEM_START;
+ if(fwrite(start,sizeof(char),sizeof(start)-1,fp)!=sizeof(start)-1) { return -1; }
+
+ return 1;
+}
+
+static int rss_entry_title(FILE *fp, const char *title) {
+ size_t len;
+
+ if(NULL==title) { return -1; }
+ len = strlen(title);
+ if(len==0) { return -1; }
+
+ const char start[] = RSS_TAG_TITLE_START;
+ if(fwrite(start,sizeof(char),sizeof(start)-1,fp)!=sizeof(start)-1) { return -1; }
+
+ if(fwrite(title,sizeof(char),len,fp)!=len) { return -1; }
+
+ const char end[] = RSS_TAG_TITLE_END;
+ if(fwrite(end,sizeof(char),sizeof(end)-1,fp)!=sizeof(end)-1) { return -1; }
+
+ return 1;
+}
--- /dev/null
+#include<rss.h>
+
+int rss_footer(FILE *fp) {
+ const char channel[] = RSS_TAG_CHANNEL_END;
+ const char rss[] = RSS_TAG_RSS_END;
+
+ if(NULL==fp) { return -1; }
+
+ if(fwrite(channel,sizeof(char),sizeof(channel)-1,fp)!=sizeof(channel)-1) { return -1; }
+ if(fwrite(rss,sizeof(char),sizeof(rss)-1,fp)!=sizeof(rss)-1) { return -1; }
+
+ return 1;
+}
--- /dev/null
+#include<rss.h>
+
+int rss_header(FILE *fp) {
+ const char rss[] = RSS_TAG_RSS_START;
+ const char channel[] = RSS_TAG_CHANNEL_START;
+
+ if(NULL==fp) { return -1; }
+
+ if(fwrite(rss,sizeof(char),sizeof(rss)-1,fp)!=sizeof(rss)-1) { return -1; }
+ if(fwrite(channel,sizeof(char),sizeof(channel)-1,fp)!=sizeof(channel)-1) { return -1; }
+
+ return 1;
+}
--- /dev/null
+#include<rss.h>
+
+static int rss_info_description(FILE*,const char*);
+static int rss_info_language(FILE*,const char*);
+static int rss_info_last_build_date(FILE*,const struct tm*);
+static int rss_info_link(FILE*,const char*);
+static int rss_info_title(FILE*,const char*);
+
+int rss_info(FILE *fp, struct rss_channel_info *info) {
+ if(NULL==fp) { return -1; }
+ if(NULL==info) { return -1; }
+
+ if(rss_info_title(fp,info->title)<0) { return -1; }
+ if(rss_info_link(fp,info->link)<0) { return -1; }
+ if(rss_info_description(fp,info->description)<0) { return -1; }
+ if(rss_info_language(fp,info->language)<0) { return -1; }
+ if(rss_info_last_build_date(fp,&(info->last_build_date))<0) { return -1; }
+
+ return 1;
+}
+
+static int rss_info_description(FILE *fp, const char *description) {
+ size_t len;
+
+ const char start[] = RSS_TAG_DESCRIPTION_START;
+ if(fwrite(start,sizeof(char),sizeof(start)-1,fp)!=sizeof(start)-1) { return -1; }
+
+ if((NULL==description)||(0==strlen(description))) {
+ const char default_description[] = RSS_DEFAULT_CHANNEL_DESCRIPTION;
+ if(fwrite(
+ default_description, /* void* ptr */
+ sizeof(char), /* size_t size */
+ sizeof(default_description)-1, /* size_t nmemb */
+ fp /* FILE *stream */
+ )!=sizeof(default_description)-1) { return -1; }
+ } else {
+ len = strlen(description);
+ if(fwrite(description,sizeof(char),len,fp)!=len) { return -1; }
+ }
+
+ const char end[] = RSS_TAG_DESCRIPTION_END;
+ if(fwrite(end,sizeof(char),sizeof(end)-1,fp)!=sizeof(end)-1) { return -1; }
+
+ return 1;
+}
+
+static int rss_info_language(FILE *fp, const char *language) {
+ size_t len;
+
+ const char start[] = RSS_TAG_LANGUAGE_START;
+ if(fwrite(start,sizeof(char),sizeof(start)-1,fp)!=sizeof(start)-1) { return -1; }
+
+ if((NULL==language)||(0==strlen(language))) {
+ const char default_language[] = RSS_DEFAULT_LANGUAGE;
+ if(fwrite(
+ default_language, /* void* ptr */
+ sizeof(char), /* size_t size */
+ sizeof(default_language)-1, /* size_t nmemb */
+ fp /* FILE *stream */
+ )!=sizeof(default_language)-1) { return -1; }
+ } else {
+ len = strlen(language);
+ if(fwrite(language,sizeof(char),len,fp)!=len) { return -1; }
+ }
+
+ const char end[] = RSS_TAG_LANGUAGE_END;
+ if(fwrite(end,sizeof(char),sizeof(end)-1,fp)!=sizeof(end)-1) { return -1; }
+
+ return 1;
+}
+
+static int rss_info_last_build_date(FILE *fp, const struct tm *date) {
+ char buf[40];
+ size_t buf_size = 40;
+
+ const char start[] = RSS_TAG_LASTBUILDDATE_START;
+ if(fwrite(start,sizeof(char),sizeof(start)-1,fp)!=sizeof(start)-1) { return -1; }
+
+ if(!(strftime(buf,buf_size, "%a, %d %b %Y %H:%M:%S %z", date))) { return -1; }
+
+ const char end[] = RSS_TAG_LASTBUILDDATE_END;
+ if(fwrite(end,sizeof(char),sizeof(end)-1,fp)!=sizeof(end)-1) { return -1; }
+
+ return 1;
+}
+
+static int rss_info_link(FILE *fp, const char *link) {
+ size_t len;
+
+ if(NULL==link) { return -1; }
+ len = strlen(link);
+ if(len==0) { return -1; }
+
+ const char start[] = RSS_TAG_LINK_START;
+ if(fwrite(start,sizeof(char),sizeof(start)-1,fp)!=sizeof(start)-1) { return -1; }
+
+ if(fwrite(link,sizeof(char),len,fp)!=len) { return -1; }
+
+ const char end[] = RSS_TAG_TITLE_END;
+ if(fwrite(end,sizeof(char),sizeof(end)-1,fp)!=sizeof(end)-1) { return -1; }
+
+ return 1;
+}
+
+static int rss_info_title(FILE *fp, const char *title) {
+ size_t len;
+
+ if(NULL==title) { return -1; }
+ len = strlen(title);
+ if(len==0) { return -1; }
+
+ const char start[] = RSS_TAG_TITLE_START;
+ if(fwrite(start,sizeof(char),sizeof(start)-1,fp)!=sizeof(start)-1) { return -1; }
+
+ if(fwrite(title,sizeof(char),len,fp)!=len) { return -1; }
+
+ const char end[] = RSS_TAG_TITLE_END;
+ if(fwrite(end,sizeof(char),sizeof(end)-1,fp)!=sizeof(end)-1) { return -1; }
+
+ return 1;
+}
#include<torrent.h>
-#define TORRENT_FILE_DIRECTORY "/torrents"
-#define TORRENT_FILE_EXTENSION ".torrent"
-
char *torrent_file_path(const char *prefix, unsigned char *infohash, size_t len) {
char *path, *p;
char hex[(crypto_hash_sha256_BYTES<<1)+1];
size_t i;
char *p;
+ // NOTE: long options defined in src/init.c
+
i = 0;
while(
!((0==long_options[i].name) &&
srand(time(NULL));
create_test_directory(TEST_DIRECTORY);
+ create_test_directory(TEST_DIRECTORY "/data");
+ create_test_directory(TEST_DIRECTORY "/feeds");
create_test_directory(TEST_DIRECTORY "/torrents");
create_test_file(TEST_FILE_1,TEST_FILE_1_CONTENTS);
create_test_file(TEST_FILE_2,TEST_FILE_2_CONTENTS);