1 /*
2
3 $Id$
4
5 G N O K I I
6
7 A Linux/Unix toolset and driver for the mobile phones.
8
9 This file is part of gnokii.
10
11 Gnokii is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 Gnokii is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with gnokii; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
25 Copyright (C) 1999-2000 Hugh Blemings & Pavel Janik ml.
26 Copyright (C) 1999-2000 Gary Reuter, Reinhold Jordan
27 Copyright (C) 1999-2006 Pawel Kot
28 Copyright (C) 2000-2002 Marcin Wiacek, Chris Kemp, Manfred Jonsson
29 Copyright (C) 2001 Marian Jancar, Bartek Klepacz
30 Copyright (C) 2001-2002 Pavel Machek, Markus Plail
31 Copyright (C) 2002 Ladis Michl, Simon Huggins
32 Copyright (C) 2002-2004 BORBELY Zoltan
33 Copyright (C) 2003 Bertrik Sikken
34 Copyright (C) 2004 Martin Goldhahn
35
36 Mainline code for gnokii utility. Phonebook functions.
37
38 */
39
40 #include "config.h"
41 #include "misc.h"
42 #include "compat.h"
43
44 #include <stdio.h>
45 #ifndef _GNU_SOURCE
46 # define _GNU_SOURCE 1
47 #endif
48 #include <getopt.h>
49
50 #include "gnokii-app.h"
51 #include "gnokii.h"
52
phonebook_usage(FILE * f)53 void phonebook_usage(FILE *f)
54 {
55 fprintf(f, _("Phonebook options:\n"
56 " --getphonebook memory_type start_number [end_number|end]\n"
57 " [[-r|--raw]|[-v|--vcard]|[-l|--ldif]]\n"
58 " --writephonebook [[-o|--overwrite]|[-f|--find-free]]\n"
59 " [-m|--memory-type|--memory memory_type]\n"
60 " [-n|--memory-location|--location number]\n"
61 " [[-v|--vcard]|[-l|--ldif]]\n"
62 " --deletephonebook memory_type start_number [end_number|end]\n"));
63 }
64
65 /* Displays usage of --getphonebook command */
getphonebook_usage(FILE * f,int exitval)66 int getphonebook_usage(FILE *f, int exitval)
67 {
68 fprintf(f, _(" usage: --getphonebook memory start [end] reads phonebook entries from memory type\n"
69 " (SM, ME, IN, OU, ...) messages starting\n"
70 " from location start and ending with end;\n"
71 " if end option is omitted, just one entry\n"
72 " is read;\n"
73 " if 'end' is used all entries are read\n"
74 " -r\n"
75 " --raw output in raw form (comma separated)\n"
76 " -v\n"
77 " --vcard output in vcard format\n"
78 " -l\n"
79 " --ldif output in ldif format\n"
80 "\n"
81 ));
82 return exitval;
83 }
84
85 /* Get requested range of memory storage entries and output to stdout in
86 easy-to-parse format */
getphonebook(int argc,char * argv[],gn_data * data,struct gn_statemachine * state)87 gn_error getphonebook(int argc, char *argv[], gn_data *data, struct gn_statemachine *state)
88 {
89 gn_phonebook_entry entry;
90 gn_memory_status memstat;
91 int i, count, start_entry, end_entry, num_entries = INT_MAX, explicit_end = true;
92 gn_error error = GN_ERR_NONE;
93 char *memory_type_string;
94 int type = 0; /* Output type:
95 0 - not formatted
96 1 - CSV
97 2 - vCard
98 3 - LDIF
99 */
100 struct option options[] = {
101 { "raw", no_argument, NULL, 'r' },
102 { "vcard", no_argument, NULL, 'v' },
103 { "ldif", no_argument, NULL, 'l' },
104 { NULL, 0, NULL, 0 }
105 };
106
107 /* Handle command line args that set type, start and end locations. */
108 memory_type_string = optarg;
109 memstat.memory_type = gn_str2memory_type(memory_type_string);
110 if (memstat.memory_type == GN_MT_XX) {
111 fprintf(stderr, _("Unknown memory type %s (use ME, SM, ...)!\n"), optarg);
112 return GN_ERR_INVALIDMEMORYTYPE;
113 }
114
115 start_entry = gnokii_atoi(argv[optind]);
116 if (errno || start_entry < 0)
117 return getphonebook_usage(stderr, -1);
118 end_entry = parse_end_value_option(argc, argv, optind + 1, start_entry);
119 if (errno || end_entry < 0)
120 return getphonebook_usage(stderr, -1);
121
122 i = getopt_long(argc, argv, "rvl", options, NULL);
123 switch (i) {
124 case 'r':
125 type = 1;
126 break;
127 case 'v':
128 type = 2;
129 break;
130 case 'l':
131 type = 3;
132 break;
133 case -1:
134 /* default */
135 break;
136 default:
137 return getphonebook_usage(stderr, -1);
138 }
139 if (argc - optind > 2) {
140 /* There are too many arguments that don't start with '-' */
141 return getphonebook_usage(stderr, -1);
142 }
143
144 if (end_entry == INT_MAX) {
145 explicit_end = false;
146 data->memory_status = &memstat;
147 if ((error = gn_sm_functions(GN_OP_GetMemoryStatus, data, state)) == GN_ERR_NONE) {
148 num_entries = memstat.used;
149 end_entry = memstat.used + memstat.free;
150 /* FIXME warn the user like parse_end_value_option() when end_entry < start_entry */
151 if (end_entry < start_entry) end_entry = start_entry;
152 }
153 }
154
155 /* Now retrieve the requested entries. */
156 count = start_entry;
157 while (num_entries > 0 && count <= end_entry) {
158 memset(&entry, 0, sizeof(gn_phonebook_entry));
159 entry.memory_type = memstat.memory_type;
160 entry.location = count;
161
162 data->phonebook_entry = &entry;
163 error = gn_sm_functions(GN_OP_ReadPhonebook, data, state);
164
165 switch (error) {
166 int i;
167 case GN_ERR_NONE:
168 if (entry.empty != false)
169 break;
170 num_entries--;
171 switch (type) {
172 case 1:
173 gn_file_phonebook_raw_write(stdout, &entry, memory_type_string);
174 break;
175 case 2: {
176 char *s;
177
178 s = gn_phonebook2vcardstr(&entry);
179 fprintf (stdout, "%s", s);
180 free (s);
181 }
182 break;
183 case 3:
184 gn_phonebook2ldif(stdout, &entry);
185 break;
186 default:
187 fprintf(stdout, _("%d. %s: %s\n"), entry.location, _("Name"), entry.name);
188 /* Print out personal information */
189 if (entry.person.has_person) {
190 if (entry.person.honorific_prefixes[0])
191 fprintf(stdout, "%s ", entry.person.honorific_prefixes);
192 if (entry.person.given_name[0])
193 fprintf(stdout, "%s ", entry.person.given_name);
194 if (entry.person.family_name[0])
195 fprintf(stdout, "%s", entry.person.family_name);
196 fprintf(stdout, "\n");
197 }
198
199 fprintf(stdout, _("%s: %s\n"), _("Caller group"), gn_phonebook_group_type2str(entry.caller_group));
200
201 /* FIXME: AT driver doesn't set subentries */
202 if (!entry.subentries_count && entry.number) {
203 fprintf(stdout, _("%s: %s\n"), _("Number"), entry.number);
204 }
205
206 /* Print out address information */
207 if (entry.address.has_address) {
208 fprintf(stdout, _("Address information:\n"));
209 if (entry.address.post_office_box[0])
210 fprintf(stdout, _(" %s: %s\n"), _("Post office address"), entry.address.post_office_box);
211 if (entry.address.extended_address[0])
212 fprintf(stdout, _(" %s: %s\n"), _("Extended address"), entry.address.extended_address);
213 if (entry.address.street[0])
214 fprintf(stdout, _(" %s: %s\n"), _("Street"), entry.address.street);
215 if (entry.address.city[0])
216 fprintf(stdout, _(" %s: %s\n"), _("City"), entry.address.city);
217 if (entry.address.state_province[0])
218 fprintf(stdout, _(" %s: %s\n"), _("State or province"), entry.address.state_province);
219 if (entry.address.zipcode[0])
220 fprintf(stdout, _(" %s: %s\n"), _("Zip code"), entry.address.zipcode);
221 if (entry.address.country[0])
222 fprintf(stdout, _(" %s: %s\n"), _("Country"), entry.address.country);
223 }
224 dprintf("subentries count: %d\n", entry.subentries_count);
225 for (i = 0; i < entry.subentries_count; i++) {
226 fprintf(stdout, "%s: ", gn_subentrytype2string(entry.subentries[i].entry_type, entry.subentries[i].number_type));
227 switch (entry.subentries[i].entry_type) {
228 case GN_PHONEBOOK_ENTRY_ExtGroup:
229 fprintf(stdout, "%d", entry.subentries[i].data.id);
230 break;
231 case GN_PHONEBOOK_ENTRY_Birthday:
232 case GN_PHONEBOOK_ENTRY_Date:
233 fprintf(stdout, _("%04u.%02u.%02u %02u:%02u:%02u"), entry.subentries[i].data.date.year, entry.subentries[i].data.date.month, entry.subentries[i].data.date.day, entry.subentries[i].data.date.hour, entry.subentries[i].data.date.minute, entry.subentries[i].data.date.second);
234 break;
235 case GN_PHONEBOOK_ENTRY_Image:
236 break;
237 default:
238 fprintf(stdout, "%s", entry.subentries[i].data.number);
239 break;
240 }
241 fprintf(stdout, "\n");
242 }
243 if ((entry.memory_type == GN_MT_MC ||
244 entry.memory_type == GN_MT_DC ||
245 entry.memory_type == GN_MT_RC) &&
246 entry.date.year)
247 fprintf(stdout, _("Date: %04u.%02u.%02u %02u:%02u:%02u\n"), entry.date.year, entry.date.month, entry.date.day, entry.date.hour, entry.date.minute, entry.date.second);
248 break;
249 }
250 break;
251 case GN_ERR_EMPTYLOCATION:
252 fprintf(stderr, _("Empty memory location. Skipping.\n"));
253 break;
254 default:
255 fprintf(stderr, _("Error reading from the location %d in memory %s\n"), count, memory_type_string);
256 fprintf(stderr, _("Error: %s\n"), gn_error_print(error));
257 /* some older phones might return GN_ERR_INVALIDLOCATION for lower numbered locations
258 so make it non fatal when a numeric end location was given */
259 if (!((error == GN_ERR_INVALIDLOCATION) && explicit_end)) {
260 return error;
261 }
262 }
263 count++;
264 }
265 /* ignore non fatal errors that might have occurred above */
266 return GN_ERR_NONE;
267 }
268
269 /* Displays usage of --getphonebook command */
writephonebook_usage(FILE * f,int exitval)270 int writephonebook_usage(FILE *f, int exitval)
271 {
272 fprintf(f, _(" usage: --writephonebook [[-o|--overwrite]|[-f|--find-free]]\n"
273 " [-m|--memory-type|--memory memory_type]\n"
274 " [-n|--memory-location|--location number]\n"
275 " [[-v|--vcard]|[-l|--ldif]]\n"
276 "\n"
277 ));
278 return exitval;
279 }
280
281 /* Read data from stdin, parse and write to phone. The parsing is relatively
282 crude and doesn't allow for much variation from the stipulated format. */
283 /* FIXME: I guess there's *very* similar code in xgnokii */
writephonebook(int argc,char * argv[],gn_data * data,struct gn_statemachine * state)284 gn_error writephonebook(int argc, char *argv[], gn_data *data, struct gn_statemachine *state)
285 {
286 gn_phonebook_entry entry;
287 gn_error error = GN_ERR_NONE;
288 gn_memory_type default_mt = GN_MT_ME; /* Default memory_type. Changed if given in the command line */
289 int default_location = 1; /* default location. Changed if given in the command line */
290 int find_free = 0; /* By default don't try to find a free location */
291 int confirm = 0; /* By default don't overwrite existing entries */
292 int type = 0; /* type of the output:
293 0 - CSV (default)
294 1 - vCard
295 2 - LDIF
296 */
297 char *line, oline[MAX_INPUT_LINE_LEN];
298 int i;
299
300 struct option options[] = {
301 { "overwrite", 0, NULL, 'o'},
302 { "vcard", 0, NULL, 'v'},
303 { "ldif", 0, NULL, 'l'},
304 { "find-free", 0, NULL, 'f'},
305 { "memory-type", required_argument, NULL, 'm'},
306 { "memory", required_argument, NULL, 'm'},
307 { "memory-location", required_argument, NULL, 'n'},
308 { "location", required_argument, NULL, 'n'},
309 { NULL, 0, NULL, 0}
310 };
311
312 /* Option parsing */
313 while ((i = getopt_long(argc, argv, "ovlfm:n:", options, NULL)) != -1) {
314 switch (i) {
315 case 'o':
316 confirm = 1;
317 break;
318 case 'v':
319 if (type)
320 return writephonebook_usage(stderr, -1);
321 type = 1;
322 break;
323 case 'l':
324 if (type)
325 return writephonebook_usage(stderr, -1);
326 type = 2;
327 break;
328 case 'f':
329 find_free = 1;
330 break;
331 case 'm':
332 default_mt = gn_str2memory_type(optarg);
333 break;
334 case 'n':
335 default_location = gnokii_atoi(optarg);
336 if (errno || default_location < 0)
337 return writephonebook_usage(stderr, -1);
338 break;
339 default:
340 return writephonebook_usage(stderr, -1);
341 }
342 }
343 if (argc > optind) {
344 /* There are too many arguments that don't start with '-' */
345 return writephonebook_usage(stderr, -1);
346 }
347
348 line = oline;
349
350 /* Go through data from stdin. */
351 while (!feof(stdin)) {
352 error = GN_ERR_NONE;
353
354 memset(&entry, 0, sizeof(gn_phonebook_entry));
355 entry.memory_type = default_mt;
356 entry.location = default_location;
357 switch (type) {
358 case 1:
359 if (gn_vcard2phonebook(stdin, &entry))
360 error = GN_ERR_WRONGDATAFORMAT;
361 break;
362 case 2:
363 if (gn_ldif2phonebook(stdin, &entry))
364 error = GN_ERR_WRONGDATAFORMAT;
365 break;
366 default:
367 if (!gn_line_get(stdin, line, MAX_INPUT_LINE_LEN))
368 goto out; /* it means we read an empty line, but that's not an error */
369 else
370 error = gn_file_phonebook_raw_parse(&entry, oline);
371 break;
372 }
373
374 if (error != GN_ERR_NONE)
375 goto out;
376
377 if (find_free) {
378 #if 0
379 error = gn_sm_functions(GN_OP_FindFreePhonebookEntry, data, state);
380 if (error == GN_ERR_NOTIMPLEMENTED) {
381 #endif
382 for (i = 1; ; i++) {
383 gn_phonebook_entry aux;
384
385 memcpy(&aux, &entry, sizeof(gn_phonebook_entry));
386 data->phonebook_entry = &aux;
387 data->phonebook_entry->location = i;
388 error = gn_sm_functions(GN_OP_ReadPhonebook, data, state);
389 if (error != GN_ERR_NONE && error != GN_ERR_EMPTYLOCATION) {
390 break;
391 }
392 if (aux.empty || error == GN_ERR_EMPTYLOCATION) {
393 entry.location = aux.location;
394 error = GN_ERR_NONE;
395 break;
396 }
397 }
398 #if 0
399 }
400 #endif
401 if (error != GN_ERR_NONE)
402 goto out;
403 }
404
405 if (!confirm) {
406 gn_phonebook_entry aux;
407
408 memcpy(&aux, &entry, sizeof(gn_phonebook_entry));
409 data->phonebook_entry = &aux;
410 error = gn_sm_functions(GN_OP_ReadPhonebook, data, state);
411
412 if (error == GN_ERR_NONE || error == GN_ERR_EMPTYLOCATION) {
413 if (!aux.empty && error != GN_ERR_EMPTYLOCATION) {
414 char ans[8] = "";
415
416 fprintf(stdout, _("Location busy. "));
417 confirm = -1;
418 while (confirm < 0) {
419 fprintf(stdout, _("Overwrite? (yes/no) "));
420 gn_line_get(stdin, ans, 7);
421 if (!strcmp(ans, _("yes")))
422 confirm = 1;
423 else if (!strcmp(ans, _("no")))
424 confirm = 0;
425 else {
426 fprintf(stdout, _("\nIncorrect answer [%s]. Assuming 'no'.\n"), ans);
427 confirm = 0;
428 }
429 }
430 /* User chose not to overwrite */
431 if (!confirm) continue;
432 confirm = 0;
433 }
434 } else {
435 goto out;
436 }
437 }
438
439 /* Do write and report success/failure. */
440 gn_phonebook_entry_sanitize(&entry);
441 data->phonebook_entry = &entry;
442 error = gn_sm_functions(GN_OP_WritePhonebook, data, state);
443
444 if (error == GN_ERR_NONE) {
445 fprintf(stderr,
446 _("Write Succeeded: memory type: %s, loc: %d, name: %s, number: %s\n"),
447 gn_memory_type2str(entry.memory_type), entry.location, entry.name, entry.number);
448 /* If the location was not specified and there are
449 * multiple entries, don't write them to the same
450 * location */
451 default_location++;
452 } else
453 fprintf(stderr, _("Write failed (%s): memory type: %s, loc: %d, name: %s, number: %s\n"),
454 gn_error_print(error), gn_memory_type2str(entry.memory_type), entry.location, entry.name, entry.number);
455 }
456 out:
457 if (error != GN_ERR_NONE)
458 fprintf(stderr, _("Write failed (%s): memory type: %s, loc: %d, name: %s, number: %s\n"),
459 gn_error_print(error), gn_memory_type2str(entry.memory_type), entry.location, entry.name, entry.number);
460 return error;
461 }
462
463 /* Displays usage of --deletephonebook command */
deletephonebook_usage(FILE * f,int exitval)464 int deletephonebook_usage(FILE *f, int exitval)
465 {
466 fprintf(f, _(" usage: --deletephonebook memory_type start_number [end_number|end]\n"
467 "\n"
468 ));
469 return exitval;
470 }
471
472 /* Delete phonebook entry */
deletephonebook(int argc,char * argv[],gn_data * data,struct gn_statemachine * state)473 gn_error deletephonebook(int argc, char *argv[], gn_data *data, struct gn_statemachine *state)
474 {
475 gn_phonebook_entry entry;
476 gn_error error;
477 char *memory_type_string;
478 int i, first_location, last_location;
479
480 if (argc < 3)
481 return deletephonebook_usage(stderr, -1);
482
483 /* Handle command line args that set memory type and location. */
484 memory_type_string = optarg;
485 entry.memory_type = gn_str2memory_type(memory_type_string);
486 if (entry.memory_type == GN_MT_XX) {
487 fprintf(stderr, _("Unknown memory type %s (use ME, SM, ...)!\n"), optarg);
488 return GN_ERR_INVALIDMEMORYTYPE;
489 }
490
491 first_location = gnokii_atoi(argv[optind]);
492 if (errno || first_location < 0)
493 return deletephonebook_usage(stderr, -1);
494 last_location = parse_end_value_option(argc, argv, optind + 1, first_location);
495 if (errno || last_location < 0)
496 return deletephonebook_usage(stderr, -1);
497
498 for (i = first_location; i <= last_location; i++) {
499 entry.location = i;
500 entry.empty = true;
501 data->phonebook_entry = &entry;
502 error = gn_sm_functions(GN_OP_DeletePhonebook, data, state);
503 switch (error) {
504 case GN_ERR_NONE:
505 fprintf (stderr, _("Phonebook entry removed: memory type: %s, loc: %d\n"),
506 gn_memory_type2str(entry.memory_type), entry.location);
507 break;
508 default:
509 if (last_location == INT_MAX)
510 last_location = 0;
511 else
512 fprintf (stderr, _("Phonebook entry removal FAILED (%s): memory type: %s, loc: %d\n"),
513 gn_error_print(error), gn_memory_type2str(entry.memory_type), entry.location);
514 break;
515 }
516 }
517 return GN_ERR_NONE;
518 }
519