]> git.datanom.net - vcard-parser.git/blob - src/vcard.c
New function
[vcard-parser.git] / src / vcard.c
1 /*
2 * vcard.c
3 *
4 * Copyright 2019 Michael Rasmussen <mir@datanom.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 #include <unistd.h>
23 #include <errno.h>
24 #include <glib/gprintf.h>
25 #include <vcard.h>
26 #include <vcard-parser.h>
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 struct _VCard {
33 VCardParserResponse state;
34 VCardVersion version;
35 GHashTable* vcard;
36 };
37
38 static char *replaceWord(const char *s, const char *oldW, const char *newW) {
39 char *result;
40 int i, cnt = 0;
41 int newWlen = strlen(newW);
42 int oldWlen = strlen(oldW);
43
44 for (i = 0; s[i] != '\0'; i++) {
45 if (strstr(&s[i], oldW) == &s[i]) {
46 cnt++;
47 i += oldWlen - 1;
48 }
49 }
50
51 result = (char *) malloc(i + cnt * (newWlen - oldWlen) + 1);
52
53 i = 0;
54 while (*s) {
55 if (strstr(s, oldW) == s) {
56 strcpy(&result[i], newW);
57 i += newWlen;
58 s += oldWlen;
59 }
60 else
61 result[i++] = *s++;
62 }
63
64 result[i] = '\0';
65 return result;
66 }
67
68 static void hash_table_cb(gpointer key, gpointer value, gpointer data) {
69 GSList* list = (GSList*) value;
70 gchar** str = (gchar**) data;
71 gchar* s = NULL;
72
73 if (!list) return;
74
75 while (list) {
76 VCardProperty* vp = (VCardProperty*) list->data;
77 gchar* s0 = replaceWord(vp->value, "\n", "\n ");
78 if (!*str)
79 s = g_strconcat(vp->name, ":", s0, NULL);
80 else {
81 s = g_strconcat(*str, "\n", vp->name, ":", s0, NULL);
82 g_free(*str);
83 }
84 g_free(s0);
85 *str = g_strdup(s);
86 g_free(s);
87 list = list->next;
88 }
89 }
90
91 static gchar** make_chunks(const gchar* text) {
92 gchar** chunks = NULL;
93 gchar* v_text = g_strdup(text);
94 g_strstrip(v_text);
95
96 gchar** tmp = g_strsplit(v_text, "END:VCARD", 0);
97 g_free(v_text);
98 guint lines = g_strv_length(tmp);
99 if (lines < 2)
100 return tmp;
101
102 if (strlen(tmp[lines-1]) < 1) {
103 chunks = g_new0(gchar*, lines);
104 lines--;
105 } else
106 chunks = g_new0(gchar*, lines + 1);
107
108 for(int i = 0; i < lines; i++) {
109 g_strchug(tmp[i]);
110 chunks[i] = g_strconcat(tmp[i], "END:VCARD", NULL);
111 }
112 g_strfreev(tmp);
113
114 return chunks;
115 }
116
117 void VCard_free(VCard* object) {
118 if (object == NULL) return;
119
120 if (object->vcard)
121 destroy_hash_table(object->vcard);
122 g_free(object);
123 }
124
125 void VCard_list_free(GSList* list) {
126 GSList* tmp = list;
127
128 while(tmp) {
129 VCard* object = (VCard*) tmp->data;
130 VCard_free(object);
131 tmp = tmp->next;
132 }
133
134 if(list)
135 g_slist_free(list);
136 }
137
138 VCard* VCard_new(VCardVersion version) {
139 VCard* vc = g_new0(VCard, 1);
140 vc->version = version;
141
142 return vc;
143 }
144
145 GSList* VCard_new_from_text(const gchar* text, VCardVersion version, gboolean skip_broken) {
146 GSList* list = NULL;
147 VCard* vc = NULL;
148
149 if (!text || strlen(text) < 1) return NULL;
150
151 gchar** chunks = make_chunks(text);
152 for (int i = 0; i < g_strv_length(chunks); i++) {
153 vc = g_new0(VCard, 1);
154 vc->version = version;
155
156 VCardParserResponse r = vcard_parse_text(chunks[i], &vc->version, &vc->vcard);
157 if (r != VCARD_PARSER_OK && skip_broken) {
158 VCard_free(vc);
159 continue;
160 }
161 vc->state = r;
162 list = g_slist_prepend(list, vc);
163 }
164 g_strfreev(chunks);
165
166 return list;
167 }
168
169 GSList* VCard_new_from_file(FILE* file, VCardVersion version, gboolean skip_broken) {
170 GSList* list = NULL;
171 VCard* vc = g_new0(VCard, 1);
172
173 vc->version = version;
174 list = g_slist_prepend(list, vc);
175
176 return list;
177 }
178
179 void VCard_print_list(GSList* list) {
180 VCard_print_list_fd(list, STDOUT_FILENO);
181 }
182
183 void VCard_print_list_fd(GSList* list, int fd) {
184 GSList* tmp = list;
185 if (fd > 0) {
186 while(tmp) {
187 VCard* object = (VCard*) tmp->data;
188 VCard_print_fd(object, fd);
189 if (tmp->next) {
190 ssize_t len = strlen("\n");
191 if (write(fd, "\n", len) < len)
192 g_warning(strerror(errno));
193 }
194 tmp = tmp->next;
195 }
196 }
197 }
198
199 void VCard_print(VCard* object){
200 VCard_print_fd(object, STDOUT_FILENO);
201 }
202
203 void VCard_print_fd(VCard* object, int fd) {
204 gchar *body = NULL, *s = NULL;
205
206 if (object && object->vcard && fd > 0) {
207 gchar* version = vcard_version_2_str(object->version);
208 s = g_strdup_printf("BEGIN:VCARD\nVERSION:%s", version);
209 g_free(version);
210 g_hash_table_foreach(object->vcard, hash_table_cb, &s);
211 body = g_strdup_printf("%s\nEND:VCARD", s);
212 g_free(s);
213 ssize_t len = strlen(body);
214 if (write(fd, body, len) < len)
215 g_warning(strerror(errno));
216 g_free(body);
217 }
218 }
219
220 gchar* VCard_get_state(VCard* object) {
221 gchar* message = NULL;
222
223 if (!object) return NULL;
224
225 switch (object->state) {
226 case VCARD_PARSER_OK:
227 message = g_strdup("OK");
228 break;
229 case VCARD_PARSER_VERSION_MISMATCH:
230 message = g_strdup("Version mismatch");
231 break;
232 case VCARD_PARSER_ATTRIBUTE_VERSION_MISMATCH:
233 message = g_strdup("Attribute not supported in this version");
234 break;
235 case VCARD_PARSER_BAD_FORMAT:
236 message = g_strdup("Bad input format");
237 break;
238 case VCARD_PARSER_ERROR:
239 message = g_strdup("Unknown error");
240 break;
241 default:
242 message = g_strdup("Unhandled error");
243 break;
244 }
245
246 return message;
247 }
248
249 GSList* VCard_get_property(VCard* object, const gchar* property) {
250 GSList *values = NULL, *tmp;
251 GSList *iter;
252 VCardProperty* vp = NULL;
253
254 if (object && object->vcard && property) {
255 tmp = g_hash_table_lookup(object->vcard, property);
256 for (iter = tmp; iter; iter = g_slist_next(iter)) {
257 vp = (VCardProperty*) iter->data;
258 values = g_slist_prepend(values, g_strdup_printf("%s:%s", vp->name, vp->value));
259 }
260 }
261
262 return values;
263 }
This page took 0.092287 seconds and 6 git commands to generate.