...
authoralex <[email protected]>
Mon, 27 Dec 2021 22:27:39 +0000 (14:27 -0800)
committeralex <[email protected]>
Mon, 27 Dec 2021 22:27:39 +0000 (14:27 -0800)
16 files changed:
Makefile.am
inc/feed.h [new file with mode: 0644]
inc/main.h
inc/rss.h [new file with mode: 0644]
inc/torrent.h
src/feed.c [new file with mode: 0644]
src/init.c
src/main.c
src/opt/set.c
src/rss/entry.c [new file with mode: 0644]
src/rss/footer.c [new file with mode: 0644]
src/rss/header.c [new file with mode: 0644]
src/rss/info.c [new file with mode: 0644]
src/torrent/path.c
src/usage.c
test/unit/test_utils.c

index 0972588bd1fbd812bfa315fce7067f1e4ff0ffc9..4480da7ee4ef613f07775a675436cfd1a03a8987 100644 (file)
@@ -17,6 +17,7 @@ seederd_SOURCES = \
        src/bencode/encode.c \
        src/block.c \
        src/default.c \
+       src/feed.c \
        src/file.c \
        src/fs/concat.c \
        src/fs/dir.c \
@@ -36,6 +37,10 @@ seederd_SOURCES = \
        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 \
@@ -57,6 +62,7 @@ seederd_SOURCES += \
        inc/bencode.h \
        inc/block.h \
        inc/default.h \
+       inc/feed.h \
        inc/file.h \
        inc/fs.h \
        inc/hash.h \
@@ -65,6 +71,7 @@ seederd_SOURCES += \
        inc/log.h \
        inc/main.h \
        inc/opt.h \
+       inc/rss.h \
        inc/server.h \
        inc/session.h \
        inc/setup.h \
diff --git a/inc/feed.h b/inc/feed.h
new file mode 100644 (file)
index 0000000..0908289
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __FEED_H_
+#define __FEED_H_
+
+#include<rss.h>
+#include<torrent.h>
+
+#define FEED_DIRECTORY PREFIX "/feeds"
+
+int feed();
+
+#endif
index 8acd425a34f3c19766f703fc2bcf164c4428a35c..7953f8a68f0f9db5e02203d8dbd8c1d81a3edad5 100644 (file)
@@ -4,6 +4,7 @@
 #include<stdlib.h>
 
 #include<add.h>
+#include<feed.h>
 #include<init.h>
 #include<server.h>
 #include<watch.h>
diff --git a/inc/rss.h b/inc/rss.h
new file mode 100644 (file)
index 0000000..adcbdb0
--- /dev/null
+++ b/inc/rss.h
@@ -0,0 +1,54 @@
+#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
index baefb8b4e59d1dc62192933e52519c22d505a570..a65a443746525024231864ab146ac7d00b17729a 100644 (file)
@@ -29,6 +29,9 @@ struct torrent {
        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**);
diff --git a/src/feed.c b/src/feed.c
new file mode 100644 (file)
index 0000000..16341ab
--- /dev/null
@@ -0,0 +1,65 @@
+#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;
+} */
index 5d6c93c00549b2fc854ab804f33422d9ddbd7010..ee405a33be650e79e666a29ca2859f1ee2509d38 100644 (file)
@@ -1,5 +1,8 @@
 #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'},
index e58a4cd9a43794aeb454def9ba724e6030221e72..d160967c00985b5458332db0ab0b2ae8130488d0 100644 (file)
@@ -6,7 +6,7 @@ int main(int argc, char **argv) {
        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) { }
index bcc814e28a3711a65366b12475b42f8687cd2ba1..6059b443df2f291bff7a82cecdff18be76c7b466 100644 (file)
@@ -5,6 +5,8 @@ struct option_lookup_table_entry {
        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},
@@ -29,5 +31,5 @@ int opt_set(const char *key, const char *value) {
        }
 
        log_err(OPT_MESSAGE_UNKNOWN_OPTION,key);
-       return 0;
+       return -1;
 }
diff --git a/src/rss/entry.c b/src/rss/entry.c
new file mode 100644 (file)
index 0000000..9874bd2
--- /dev/null
@@ -0,0 +1,135 @@
+#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;
+}
diff --git a/src/rss/footer.c b/src/rss/footer.c
new file mode 100644 (file)
index 0000000..818520d
--- /dev/null
@@ -0,0 +1,13 @@
+#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;
+}
diff --git a/src/rss/header.c b/src/rss/header.c
new file mode 100644 (file)
index 0000000..985955f
--- /dev/null
@@ -0,0 +1,13 @@
+#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;
+}
diff --git a/src/rss/info.c b/src/rss/info.c
new file mode 100644 (file)
index 0000000..2d0317c
--- /dev/null
@@ -0,0 +1,121 @@
+#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;
+}
index eb50ba7a0a7b256473c4f7a535ee01e9f3f9c4ff..44ff9f8f0009d780cb3a9c771eb6a6a8eb116e8c 100644 (file)
@@ -1,8 +1,5 @@
 #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];
index 19d49708daa0518ad9829ee08735fa1d1e8724be..5c929e89bbeb614ae58dae3e0d152a155ec68f22 100644 (file)
@@ -18,6 +18,8 @@ static void usage_print_options() {
        size_t i;
        char *p;
 
+       // NOTE: long options defined in src/init.c
+
        i = 0;
        while(
                !((0==long_options[i].name) &&
index 4ae2891b18127bde504023a4bcc7538fd1547e32..1ce8027316fab9fd4662e5066e6fbd3a7eca4ca7 100644 (file)
@@ -18,6 +18,8 @@ void setup_env() {
        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);