]>
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 | ||
0d68a955 MR |
138 | VCard* VCard_new(VCardVersion version) { |
139 | VCard* vc = g_new0(VCard, 1); | |
140 | vc->version = version; | |
141 | ||
142 | return vc; | |
143 | } | |
0d68a955 MR |
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; | |
aa039bee | 263 | } |