]> code.citadel.org Git - citadel.git/blob - rss2ctdl/main.c
Clean up the RSS feed. Attempt to read If-Modified-Since header.
[citadel.git] / rss2ctdl / main.c
1 /*
2  * $Id$
3  *
4  * rss2ctdl -- a utility to pull RSS feeds into Citadel rooms.
5  * 
6  * Main program is (c)2004 by Art Cancro
7  * RSS parser is (c)2003-2004 by Oliver Feiler
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23  
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <time.h>
32 #include <signal.h>
33 #include <sys/wait.h>
34
35 #include "config.h"
36 #include "main.h"
37 #include "io-internal.h"
38 #include "conversions.h"
39 #include "md5.h"
40 #include "digcalc.h"
41
42 struct feed *first_ptr = NULL;
43 struct entity *first_entity = NULL;
44
45 /*
46  * If you want to use a proxy server, you can hack the following two lines.
47  */
48 char *proxyname = "";
49 unsigned short proxyport = 0;
50
51 /*
52  * Main function of program.
53  */
54 int main (int argc, char *argv[]) {
55         struct feed *new_ptr;
56         char *url;
57         char tmp[512];
58         struct newsitem *itemptr;
59         FILE *fp;
60         char md5msgid[256];
61         MD5_CTX md5context;
62         HASHHEX md5context_hex;
63         
64 #ifdef LOCALEPATH
65         setlocale (LC_ALL, "");
66         bindtextdomain ("rss2ctdl", LOCALEPATH);
67         textdomain ("rss2ctdl");
68 #endif
69
70         if (argc != 5) {
71                 fprintf(stderr,
72                         "%s: usage:\n %s <feedurl> <roomname> <nodefqdn> <ctdldir>\n",
73                         argv[0], argv[0]);
74                 exit(1);
75         }
76
77         /* Init the pRNG. See about.c for usages of rand() ;) */
78         srand(time(0));
79
80         url = strdup(argv[1]);
81         CleanupString(url, 0);
82
83         /* Support that stupid feed:// "protocol" */
84         if (strncasecmp (url, "feed://", 7) == 0)
85                 memcpy (url, "http", 4);
86         
87         /* If URL does not start with the procotol specification,
88         assume http://
89         -> tmp[512] -> we can "only" use max 504 chars from url ("http://" == 7). */
90         if ((strncasecmp (url, "http://", 7) != 0) &&
91                 (strncasecmp (url, "https://", 8) != 0)) {
92                 if (strlen (url) < 504) {
93                         strcpy (tmp, "http://");
94                         strncat (tmp, url, 504);
95                         free (url);
96                         url = strdup (tmp);
97                 } else {
98                         free (url);
99                         return 2;
100                 }
101         }
102
103         new_ptr = malloc (sizeof(struct feed));
104         new_ptr->feedurl = strdup(url);
105         new_ptr->feed = NULL;
106         new_ptr->content_length = 0;
107         new_ptr->title = NULL;
108         new_ptr->link = NULL;
109         new_ptr->description = NULL;
110         new_ptr->lastmodified = NULL;
111         new_ptr->lasthttpstatus = 0;
112         new_ptr->content_type = NULL;
113         new_ptr->netio_error = NET_ERR_OK;
114         new_ptr->connectresult = 0;
115         new_ptr->cookies = NULL;
116         new_ptr->authinfo = NULL;
117         new_ptr->servauth = NULL;
118         new_ptr->items = NULL;
119         new_ptr->problem = 0;
120         new_ptr->original = NULL;
121         
122         /* Don't need url text anymore. */
123         free (url);
124
125         /* Download new feed and DeXMLize it. */        
126         if ((UpdateFeed (new_ptr)) != 0) {
127                 exit(1);
128         }
129
130         sprintf(tmp, "%s/network/spoolin/rssfeed.%ld", argv[4], time(NULL));
131         fp = fopen(tmp, "w");
132         if (fp == NULL) {
133                 fprintf(stderr, "%s: cannot open %s: %s\n",
134                         argv[0], tmp, strerror(errno));
135                 exit(errno);
136         }
137
138         for (itemptr = new_ptr->items; itemptr != NULL; itemptr = itemptr->next_ptr) {
139                 fprintf(stderr, "--> %s\n", itemptr->data->title);
140                 fprintf(fp, "%c", 255);                 /* Start of message */
141                 fprintf(fp, "A");                       /* Non-anonymous */
142                 fprintf(fp, "%c", 4);                   /* MIME */
143                 fprintf(fp, "Prss%c", 0);               /* path */
144
145                 /* The message ID will be an MD5 hash of the GUID.
146                  * If there is no GUID present, we construct a message ID based
147                  * on an MD5 hash of each item.  Citadel's loopzapper will automatically
148                  * reject items with message ID's which have already been submitted.
149                  */
150                 MD5Init(&md5context);
151                 if (itemptr->data->guid != NULL) {
152                         MD5Update(&md5context, itemptr->data->guid, strlen(itemptr->data->guid));
153                 }
154                 else {
155                         if (itemptr->data->title != NULL) {
156                                 MD5Update(&md5context, itemptr->data->title, strlen(itemptr->data->title));
157                         }
158                         //if (itemptr->data->description != NULL) {
159                                 //MD5Update(&md5context, itemptr->data->description, strlen(itemptr->data->description));
160                         //}
161                         if (itemptr->data->link != NULL) {
162                                 MD5Update(&md5context, itemptr->data->link, strlen(itemptr->data->link));
163                         }
164                 }
165                 MD5Final(md5msgid, &md5context);
166                 CvtHex(md5msgid, md5context_hex);
167
168                 fprintf(fp, "I%s@%s%c", md5context_hex, argv[3], 0);    /* ID */ 
169
170                 fprintf(fp, "T%ld%c",  time(NULL),  0); /* time */
171                 fprintf(fp, "Arss%c", 0);               /* author */
172                 fprintf(fp, "O%s%c", argv[2], 0);       /* room */
173                 fprintf(fp, "C%s%c", argv[2], 0);       /* room */
174                 fprintf(fp, "N%s%c", argv[3], 0);       /* orig node */
175                 if (itemptr->data->guid != NULL) {
176                         fprintf(fp, "E%s%c", itemptr->data->guid, 0);   /* guid=euid*/
177                 }
178                 if (itemptr->data->title != NULL) {
179                         fprintf(fp, "U%s%c", itemptr->data->title, 0);  /* subject */
180                 }
181
182                 fprintf(fp, "M");                       /* msg text */
183                 fprintf(fp, "Content-type: text/html\r\n\r\n");
184                 fprintf(fp, "<HTML><BODY>\r\n");
185                 fprintf(fp, "%s\n", itemptr->data->description);
186                 if (itemptr->data->link != NULL) {
187                         fprintf(fp, "<BR><BR>\r\n");
188                         fprintf(fp, "<A HREF=\"%s\">%s</A>\n",
189                                 itemptr->data->link,
190                                 itemptr->data->link);
191                 }
192                 fprintf(fp, "</BODY></HTML>\r\n");
193                 fprintf(fp, "%c", 0);
194         }
195
196         fclose(fp);
197
198         /* Be lazy and let the operating system free all the memory. */
199         return(0);
200 }