Require atom entries to have ID, title and authors
[cascardo/atompub.git] / atom / entry.c
1 /*
2  *  Copyright (C) 2008  Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License along
15  *  with this program; if not, write to the Free Software Foundation, Inc.,
16  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19
20 #include <atompub/atom.h>
21
22 #include <glib.h>
23 #include <libxml/tree.h>
24 #include <libxml/parser.h>
25
26 struct _atom_entry
27 {
28   xmlDocPtr doc;
29   AtomID *id;
30   char *title;
31   GPtrArray *authors;
32   GPtrArray *categories;
33   char *summary;
34 };
35
36 void atom_entry_author_add (AtomEntry *, AtomPerson *);
37 static void atom_entry_authors_delete (AtomEntry *);
38
39 void atom_entry_category_add (AtomEntry *, AtomCategory *);
40 static void atom_entry_categories_delete (AtomEntry *);
41
42 AtomEntry *
43 atom_entry_new (char *id, char *title, AtomPerson *author)
44 {
45   AtomEntry *entry;
46   entry = g_slice_new (AtomEntry);
47   entry->doc = NULL;
48   entry->id = atom_id_new (id);
49   entry->title = g_strdup (title);
50   entry->authors = NULL;
51   entry->categories = NULL;
52   atom_entry_author_add (entry, author);
53   entry->summary = NULL;
54   return entry;
55 }
56
57 AtomEntry *
58 atom_entry_new_data_len (char *data, size_t len)
59 {
60   AtomEntry *entry;
61   xmlNodePtr root;
62   xmlNodePtr child;
63   entry = g_slice_new0 (AtomEntry);
64   entry->doc = xmlReadMemory (data, len, NULL, NULL,
65                               XML_PARSE_RECOVER | XML_PARSE_NOERROR);
66   if (entry->doc == NULL ||
67       (root = xmlDocGetRootElement (entry->doc)) == NULL)
68     {
69       g_slice_free (AtomEntry, entry);
70       return NULL;
71     }
72   if (xmlStrcmp (root->name, "entry"))
73     {
74       xmlFreeDoc (entry->doc);
75       g_slice_free (AtomEntry, entry);
76       return NULL;
77     }
78   for (child = root->xmlChildrenNode; child != NULL; child = child->next)
79     {
80       char * content;
81       content = xmlNodeGetContent (child->xmlChildrenNode);
82       if (!xmlStrcmp (child->name, "id"))
83         entry->id = atom_id_new (content);
84       else if (!xmlStrcmp (child->name, "title"))
85         entry->title = g_strdup (content);
86       else if (!xmlStrcmp (child->name, "summary"))
87         entry->summary = g_strdup (content);
88       else if (!xmlStrcmp (child->name, "author"))
89         atom_entry_author_add (entry, atom_person_new_from_xmlnode (child));
90       else if (!xmlStrcmp (child->name, "category"))
91         atom_entry_category_add (entry, atom_category_new_from_xmlnode (child));
92       else
93         xmlFree (content);
94     }
95   if (entry->id == NULL || entry->title == NULL || entry->authors == NULL)
96     {
97       atom_entry_delete (entry);
98       return NULL;
99     }
100   return entry;
101 }
102
103 void
104 atom_entry_delete (AtomEntry *entry)
105 {
106   if (entry->doc)
107     xmlFreeDoc (entry->doc);
108   if (entry->id)
109     atom_id_delete (entry->id);
110   if (entry->title)
111     g_free (entry->title);
112   if (entry->authors)
113     atom_entry_authors_delete (entry);
114   if (entry->categories)
115     atom_entry_categories_delete (entry);
116   if (entry->summary)
117     g_free (entry->summary);
118   g_slice_free (AtomEntry, entry);
119 }
120
121 AtomID *
122 atom_entry_id (AtomEntry *entry)
123 {
124   return entry->id;
125 }
126
127 void
128 atom_entry_id_set (AtomEntry *entry, AtomID *id)
129 {
130   if (id == NULL)
131     return;
132   if (entry->id)
133     atom_id_delete (entry->id);
134   entry->id = id;
135 }
136
137 char *
138 atom_entry_title (AtomEntry *entry)
139 {
140   return entry->title;
141 }
142
143 void
144 atom_entry_title_set (AtomEntry *entry, char *title)
145 {
146   if (title == NULL)
147     return;
148   if (entry->title)
149     g_free (title);
150   entry->title = g_strdup (title);
151 }
152
153 void
154 atom_entry_authors (AtomEntry *entry, AtomPerson *** authors, size_t *len)
155 {
156   if (len)
157     *len = entry->authors->len;
158   if (authors)
159     *authors = entry->authors->pdata;
160 }
161
162 void
163 atom_entry_author_add (AtomEntry *entry, AtomPerson *author)
164 {
165   if (entry->authors == NULL)
166     {
167       entry->authors = g_ptr_array_new ();
168     }
169   g_ptr_array_add (entry->authors, author);
170 }
171
172 static void
173 atom_entry_authors_delete (AtomEntry *entry)
174 {
175   size_t len = entry->authors->len;
176   int i;
177   for (i = 0; i < len; i++)
178     atom_person_delete (g_ptr_array_index (entry->authors, i));
179   g_ptr_array_free (entry->authors, TRUE);
180 }
181
182 void
183 atom_entry_categories (AtomEntry *entry, AtomCategory *** categories,
184                        size_t *len)
185 {
186   if (len)
187     *len = entry->categories->len;
188   if (categories)
189     *categories = entry->categories->pdata;
190 }
191
192 void
193 atom_entry_category_add (AtomEntry *entry, AtomCategory *category)
194 {
195   g_ptr_array_add (entry->categories, category);
196   if (entry->categories == NULL)
197     {
198       entry->categories = g_ptr_array_new ();
199     }
200   g_ptr_array_add (entry->categories, category);
201 }
202
203 static void
204 atom_entry_categories_delete (AtomEntry *entry)
205 {
206   size_t len = entry->categories->len;
207   int i;
208   for (i = 0; i < len; i++)
209     atom_category_delete (g_ptr_array_index (entry->categories, i));
210   g_ptr_array_free (entry->categories, TRUE);
211 }
212
213 char *
214 atom_entry_summary (AtomEntry *entry)
215 {
216   return entry->summary;
217 }
218
219 void
220 atom_entry_summary_set (AtomEntry *entry, char *summary)
221 {
222   if (entry->summary)
223     g_free (entry->summary);
224   entry->summary = g_strdup (summary);
225 }
226
227 static void
228 atom_entry_update_xmlnode (AtomEntry *entry)
229 {
230   xmlNodePtr root;
231   xmlNodePtr id;
232   xmlNodePtr title;
233   xmlNodePtr summary;
234   xmlNodePtr author;
235   xmlNodePtr cat;
236   int i;
237   if (entry->doc == NULL)
238     {
239       entry->doc = xmlNewDoc ("1.0");
240       root = xmlNewNode (NULL, "entry");
241       xmlNewNs (root, ATOM_NAMESPACE, NULL);
242       xmlDocSetRootElement (entry->doc, root);
243     }
244   else
245     {
246       xmlNodePtr child;
247       xmlNodePtr next;
248       root = xmlDocGetRootElement (entry->doc);
249       child = root->xmlChildrenNode;
250       while (child != NULL)
251         {
252           next = child->next;
253           if (!xmlStrcmp (child->name, "id") ||
254               !xmlStrcmp (child->name, "title") ||
255               !xmlStrcmp (child->name, "summary") ||
256               !xmlStrcmp (child->name, "author") ||
257               !xmlStrcmp (child->name, "category"))
258             {
259               xmlUnlinkNode (child);
260               xmlFreeNode (child);
261             }
262           child = next;
263         }
264     }
265   id = xmlNewTextChild (root, NULL, "id", atom_id_string (entry->id));
266   title = xmlNewTextChild (root, NULL, "title", entry->title);
267   if (entry->summary)
268     summary = xmlNewTextChild (root, NULL, "summary", entry->summary);
269   for (i = 0; i < entry->authors->len; i++)
270     {
271       AtomPerson *person;
272       person = g_ptr_array_index (entry->authors, i);
273       author = atom_person_to_xmlnode (person, "author");
274       xmlAddChild (root, author);
275     }
276   for (i = 0; entry->categories && i < entry->categories->len; i++)
277     {
278       AtomCategory *category;
279       category = g_ptr_array_index (entry->categories, i);
280       cat = atom_category_to_xmlnode (category, "category");
281       xmlAddChild (root, category);
282     }
283 }
284
285 void
286 atom_entry_string (AtomEntry *entry, char **buffer, size_t *len)
287 {
288   atom_entry_update_xmlnode (entry);
289   xmlDocDumpMemory (entry->doc, buffer, len);
290 }
291
292 xmlNodePtr
293 atom_entry_to_xmlnode (AtomEntry *entry)
294 {
295   atom_entry_update_xmlnode (entry);
296   return xmlCopyNodeList (xmlDocGetRootElement (entry->doc));
297 }