]>
Commit | Line | Data |
---|---|---|
aa039bee MR |
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 | ||
0d68a955 MR |
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 | |
aa039bee MR |
31 | |
32 | struct _VCard { | |
0d68a955 MR |
33 | VCardParserResponse state; |
34 | VCardVersion version; | |
35 | GHashTable* vcard; | |
aa039bee MR |
36 | }; |
37 | ||
0d68a955 MR |
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 | /* | |
139 | VCard* VCard_new(VCardVersion version) { | |
140 | VCard* vc = g_new0(VCard, 1); | |
141 | vc->version = version; | |
142 | ||
143 | return vc; | |
144 | } | |
145 | */ | |
146 | ||
147 | GSList* VCard_new_from_text(const gchar* text, VCardVersion version, gboolean skip_broken) { | |
148 | GSList* list = NULL; | |
149 | VCard* vc = NULL; | |
150 | ||
151 | if (!text || strlen(text) < 1) return NULL; | |
152 | ||
153 | gchar** chunks = make_chunks(text); | |
154 | for (int i = 0; i < g_strv_length(chunks); i++) { | |
155 | vc = g_new0(VCard, 1); | |
156 | vc->version = version; | |
157 | ||
158 | VCardParserResponse r = vcard_parse_text(chunks[i], &vc->version, &vc->vcard); | |
159 | if (r != VCARD_PARSER_OK && skip_broken) { | |
160 | VCard_free(vc); | |
161 | continue; | |
162 | } | |
163 | vc->state = r; | |
164 | list = g_slist_prepend(list, vc); | |
165 | } | |
166 | g_strfreev(chunks); | |
167 | ||
168 | return list; | |
169 | } | |
170 | ||
171 | GSList* VCard_new_from_file(FILE* file, VCardVersion version, gboolean skip_broken) { | |
172 | GSList* list = NULL; | |
173 | VCard* vc = g_new0(VCard, 1); | |
174 | ||
175 | vc->version = version; | |
176 | list = g_slist_prepend(list, vc); | |
177 | ||
178 | return list; | |
179 | } | |
180 | ||
181 | void VCard_print_list(GSList* list) { | |
182 | VCard_print_list_fd(list, STDOUT_FILENO); | |
183 | } | |
184 | ||
185 | void VCard_print_list_fd(GSList* list, int fd) { | |
186 | GSList* tmp = list; | |
187 | if (fd > 0) { | |
188 | while(tmp) { | |
189 | VCard* object = (VCard*) tmp->data; | |
190 | VCard_print_fd(object, fd); | |
191 | if (tmp->next) { | |
192 | ssize_t len = strlen("\n"); | |
193 | if (write(fd, "\n", len) < len) | |
194 | g_warning(strerror(errno)); | |
195 | } | |
196 | tmp = tmp->next; | |
197 | } | |
198 | } | |
199 | } | |
200 | ||
201 | void VCard_print(VCard* object){ | |
202 | VCard_print_fd(object, STDOUT_FILENO); | |
203 | } | |
204 | ||
205 | void VCard_print_fd(VCard* object, int fd) { | |
206 | gchar *body = NULL, *s = NULL; | |
207 | ||
208 | if (object && object->vcard && fd > 0) { | |
209 | gchar* version = vcard_version_2_str(object->version); | |
210 | s = g_strdup_printf("BEGIN:VCARD\nVERSION:%s", version); | |
211 | g_free(version); | |
212 | g_hash_table_foreach(object->vcard, hash_table_cb, &s); | |
213 | body = g_strdup_printf("%s\nEND:VCARD", s); | |
214 | g_free(s); | |
215 | ssize_t len = strlen(body); | |
216 | if (write(fd, body, len) < len) | |
217 | g_warning(strerror(errno)); | |
218 | g_free(body); | |
219 | } | |
220 | } | |
221 | ||
222 | gchar* VCard_get_state(VCard* object) { | |
223 | gchar* message = NULL; | |
224 | ||
225 | if (!object) return NULL; | |
226 | ||
227 | switch (object->state) { | |
228 | case VCARD_PARSER_OK: | |
229 | message = g_strdup("OK"); | |
230 | break; | |
231 | case VCARD_PARSER_VERSION_MISMATCH: | |
232 | message = g_strdup("Version mismatch"); | |
233 | break; | |
234 | case VCARD_PARSER_ATTRIBUTE_VERSION_MISMATCH: | |
235 | message = g_strdup("Attribute not supported in this version"); | |
236 | break; | |
237 | case VCARD_PARSER_BAD_FORMAT: | |
238 | message = g_strdup("Bad input format"); | |
239 | break; | |
240 | case VCARD_PARSER_ERROR: | |
241 | message = g_strdup("Unknown error"); | |
242 | break; | |
243 | default: | |
244 | message = g_strdup("Unhandled error"); | |
245 | break; | |
246 | } | |
247 | ||
248 | return message; | |
249 | } | |
250 | ||
251 | GSList* VCard_get_property(VCard* object, const gchar* property) { | |
252 | GSList *values = NULL, *tmp; | |
253 | GSList *iter; | |
254 | VCardProperty* vp = NULL; | |
255 | ||
256 | if (object && object->vcard && property) { | |
257 | tmp = g_hash_table_lookup(object->vcard, property); | |
258 | for (iter = tmp; iter; iter = g_slist_next(iter)) { | |
259 | vp = (VCardProperty*) iter->data; | |
260 | values = g_slist_prepend(values, g_strdup_printf("%s:%s", vp->name, vp->value)); | |
261 | } | |
262 | } | |
263 | ||
264 | return values; | |
aa039bee | 265 | } |