1 /*
2  * libEtPan! -- a mail stuff library
3  *
4  * Copyright (C) 2001, 2005 - DINH Viet Hoa
5  * Copyright (C) 2006 Andrej Kacian <andrej@kacian.sk>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the libEtPan! project nor the names of its
17  *    contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 
37 #include "parser_atom10.h"
38 
39 #include <string.h>
40 
41 #include "newsfeed.h"
42 #include "newsfeed_item.h"
43 #include "newsfeed_private.h"
44 #include "date.h"
45 #include "parser.h"
46 
47 enum {
48   FEED_LOC_ATOM10_NONE,
49   FEED_LOC_ATOM10_ENTRY,
50   FEED_LOC_ATOM10_AUTHOR
51 };
52 
newsfeed_parser_atom10_start(void * data,const char * el,const char ** attr)53 void newsfeed_parser_atom10_start(void * data, const char * el, const char ** attr)
54 {
55   struct newsfeed_parser_context * ctx;
56   int r;
57 
58   ctx = data;
59 
60   if (ctx->depth == 1) {
61     if (strcasecmp(el, "entry") == 0) {
62       /* Start of new feed item found.
63        * Create a new FeedItem, freeing the one we already have, if any. */
64       if( ctx->curitem != NULL )
65         newsfeed_item_free(ctx->curitem);
66 
67       ctx->curitem = newsfeed_item_new(ctx->feed);
68       if (ctx->curitem == NULL) {
69         ctx->error = NEWSFEED_ERROR_MEMORY;
70         return;
71       }
72 
73       ctx->location = FEED_LOC_ATOM10_ENTRY;
74     }
75     else if (strcasecmp(el, "author") == 0) {
76       /* Start of author info for the feed found.
77        * Set correct location. */
78       ctx->location = FEED_LOC_ATOM10_AUTHOR;
79     }
80     else {
81       ctx->location = FEED_LOC_ATOM10_NONE;
82     }
83   }
84   else if (ctx->depth == 2) {
85     if (strcasecmp(el, "author") == 0) {
86       /* Start of author info for current feed item.
87        * Set correct location. */
88       ctx->location = FEED_LOC_ATOM10_AUTHOR;
89     }
90     else if (strcasecmp(el, "link") == 0) {
91       const char * url;
92 
93       /* Capture item URL, from the "url" XML attribute. */
94       url = newsfeed_parser_get_attribute_value(attr, "href");
95       r = newsfeed_item_set_url(ctx->curitem, url);
96       if (r < 0) {
97         ctx->error = NEWSFEED_ERROR_MEMORY;
98         return;
99       }
100       ctx->location = FEED_LOC_ATOM10_ENTRY;
101     }
102     else {
103       ctx->location = FEED_LOC_ATOM10_ENTRY;
104     }
105   }
106 
107   ctx->depth ++;
108 }
109 
newsfeed_parser_atom10_end(void * data,const char * el)110 void newsfeed_parser_atom10_end(void *data, const char * el)
111 {
112   struct newsfeed_parser_context * ctx;
113   struct newsfeed * feed;
114   char * text;
115   int r;
116 
117   ctx = data;
118   feed = ctx->feed;
119   text = ctx->str->str;
120 
121   ctx->depth --;
122 
123   switch (ctx->depth) {
124   case 0:
125     if (strcasecmp(el, "feed") == 0) {
126       /* We have finished parsing the feed. */
127     }
128     break;
129 
130   case 1:
131     /* decide if we just received </entry>, so we can
132      * add a complete item to feed */
133     if (strcasecmp(el, "entry") == 0) {
134       /* append the complete feed item */
135       r = newsfeed_add_item(ctx->feed, ctx->curitem);
136       if (r < 0) {
137         ctx->error = NEWSFEED_ERROR_MEMORY;
138         return;
139       }
140 
141       /* since it's in the linked list, lose this pointer */
142       ctx->curitem = NULL;
143     }
144     else if (strcasecmp(el, "title") == 0) {
145       /* so it wasn't end of item */
146       r = newsfeed_set_title(feed, text);
147       if (r < 0) {
148         ctx->error = NEWSFEED_ERROR_MEMORY;
149         return;
150       }
151     }
152     else if (strcasecmp(el, "summary") == 0) {
153       r = newsfeed_set_description(feed, text);
154       if (r < 0) {
155         ctx->error = NEWSFEED_ERROR_MEMORY;
156         return;
157       }
158     }
159     else if (strcasecmp(el, "updated") == 0) {
160       time_t date;
161 
162       date = newsfeed_iso8601_date_parse(text);
163       newsfeed_set_date(feed, date);
164     }
165     /* TODO: add more later */
166     break;
167 
168   case 2:
169     if( ctx->curitem == NULL )
170       break;
171 
172     switch(ctx->location) {
173     case FEED_LOC_ATOM10_ENTRY:
174       /* We're in feed/entry */
175       if (strcasecmp(el, "title") == 0) {
176         r = newsfeed_item_set_title(ctx->curitem, text);
177         if (r < 0) {
178           ctx->error = NEWSFEED_ERROR_MEMORY;
179           return;
180         }
181       }
182       else if (strcasecmp(el, "summary") == 0) {
183         r = newsfeed_item_set_summary(ctx->curitem, text);
184         if (r < 0) {
185           ctx->error = NEWSFEED_ERROR_MEMORY;
186           return;
187         }
188       }
189       else if (strcasecmp(el, "content") == 0) {
190         r = newsfeed_item_set_text(ctx->curitem, text);
191         if (r < 0) {
192           ctx->error = NEWSFEED_ERROR_MEMORY;
193           return;
194         }
195       }
196       else if (strcasecmp(el, "id") == 0) {
197         r = newsfeed_item_set_id(ctx->curitem, text);
198         if (r < 0) {
199           ctx->error = NEWSFEED_ERROR_MEMORY;
200           return;
201         }
202       }
203       else if (strcasecmp(el, "issued") == 0) {
204         time_t date;
205 
206         date = newsfeed_iso8601_date_parse(text);
207         newsfeed_item_set_date_published(ctx->curitem, date);
208       }
209       else if (strcasecmp(el, "updated") == 0) {
210         time_t date;
211 
212         date = newsfeed_iso8601_date_parse(text);
213         newsfeed_item_set_date_modified(ctx->curitem, date);
214       }
215       break;
216 
217     case FEED_LOC_ATOM10_AUTHOR:
218       /* We're in feed/author */
219       if (strcasecmp(el, "name") == 0) {
220         r = newsfeed_item_set_author(ctx->curitem, text);
221         if (r < 0) {
222           ctx->error = NEWSFEED_ERROR_MEMORY;
223           return;
224         }
225       }
226       /* TODO: construct a "Na Me <add@dre.ss>" string
227        * from available tags */
228 
229       break;
230     }
231 
232     break;
233 
234   case 3:
235     if (ctx->curitem == NULL)
236       break;
237 
238     if (ctx->location == FEED_LOC_ATOM10_AUTHOR) {
239       /* We're in feed/entry/author */
240       if (strcasecmp(el, "name") == 0) {
241         r = newsfeed_item_set_author(ctx->curitem, text);
242         if (r < 0) {
243           ctx->error = NEWSFEED_ERROR_MEMORY;
244           return;
245         }
246       }
247     }
248 
249     break;
250   }
251 
252   mmap_string_truncate(ctx->str, 0);
253 }
254