1
// *************************************************************************
6
// * Purpose: phonebook management program
8
// * Author: Peter Hofmann (software@pxh.de)
10
// * Created: 24.6.1999
11
// *************************************************************************
14
#include <gsm_config.h>
16
#include <gsmlib/gsm_nls.h>
19
#include <gsmlib/gsm_win32_serial.h>
21
#include <gsmlib/gsm_unix_serial.h>
24
#if defined(HAVE_GETOPT_LONG) || defined(WIN32)
30
#include <gsmlib/gsm_me_ta.h>
31
#include <gsmlib/gsm_util.h>
32
#include <gsmlib/gsm_sorted_phonebook.h>
36
using namespace gsmlib;
38
#ifdef HAVE_GETOPT_LONG
39
static struct option longOpts[] =
41
{"xonxoff", no_argument, (int*)NULL, 'X'},
42
{"phonebook", required_argument, (int*)NULL, 'p'},
43
{"init", required_argument, (int*)NULL, 'I'},
44
{"destination", required_argument, (int*)NULL, 'd'},
45
{"source", required_argument, (int*)NULL, 's'},
46
{"destination-backend", required_argument, (int*)NULL, 'D'},
47
{"source-backend", required_argument, (int*)NULL, 'S'},
48
{"baudrate", required_argument, (int*)NULL, 'b'},
49
{"charset", required_argument, (int*)NULL, 't'},
50
{"copy", no_argument, (int*)NULL, 'c'},
51
{"synchronize", no_argument, (int*)NULL, 'y'},
52
{"help", no_argument, (int*)NULL, 'h'},
53
{"version", no_argument, (int*)NULL, 'v'},
54
{"verbose", no_argument, (int*)NULL, 'V'},
55
{"indexed", no_argument, (int*)NULL, 'i'},
56
{(char*)NULL, 0, (int*)NULL, 0}
59
#define getopt_long(argc, argv, options, longopts, indexptr) \
60
getopt(argc, argv, options)
63
// insert those entries from sourcePhonebook into destPhonebook
64
// that are not already present in destPhonebook
66
void insertNotPresent(SortedPhonebookRef sourcePhonebook,
67
SortedPhonebookRef destPhonebook,
68
bool indexed, bool verbose)
70
for (SortedPhonebookBase::iterator i = sourcePhonebook->begin();
71
i != sourcePhonebook->end(); ++i)
73
pair<SortedPhonebookBase::iterator, SortedPhonebookBase::iterator> range;
76
int index = i->index();
77
range = destPhonebook->equal_range(index);
81
string text = i->text();
82
range = destPhonebook->equal_range(text);
85
// do nothing if the entry is already present in the destination
86
bool alreadyPresent = false;
87
for (SortedPhonebookBase::iterator j = range.first;
88
j != range.second; ++j)
90
i->setUseIndex(indexed);
91
if (i->telephone() == j->telephone())
93
alreadyPresent = true;
102
cout << stringPrintf(_("inserting '%s' tel# %s"),
103
i->text().c_str(), i->telephone().c_str());
105
cout << stringPrintf(_(" (index #%d)"), i->index());
108
i->setUseIndex(indexed);
109
destPhonebook->insert(*i); // insert
114
// update those entries in destPhonebook, that
115
// - have the same name as one entry in destPhonebook
116
// - but have a different telephone number
117
// this is only done if the name in question is unique in the destPhonebook
118
// the case of several entries having the same in the sourcePhonebook
119
// is handled - only the first is considered for updating
121
void updateEntries(SortedPhonebookRef sourcePhonebook,
122
SortedPhonebookRef destPhonebook,
125
bool firstLoop = true;
128
for (SortedPhonebookBase::iterator i = sourcePhonebook->begin();
129
i != sourcePhonebook->end(); ++i)
131
string text = i->text();
132
if (! firstLoop && text != lastText)
134
pair<SortedPhonebookBase::iterator,
135
SortedPhonebookBase::iterator> range =
136
destPhonebook->equal_range(text);
138
SortedPhonebookBase::iterator first = range.first;
139
if (first != destPhonebook->end() && range.second == ++first)
140
{ // just one text in the destPhonebook
141
if (! (*range.first == *i)) // overwrite if different in destination
144
cout << stringPrintf(_("updating '%s' tel# %s to new tel# %s"),
145
range.first->text().c_str(),
146
range.first->telephone().c_str(),
147
i->telephone().c_str())
159
// the same but for indexed phonebooks
161
void updateEntriesIndexed(SortedPhonebookRef sourcePhonebook,
162
SortedPhonebookRef destPhonebook,
165
for (SortedPhonebookBase::iterator i = sourcePhonebook->begin();
166
i != sourcePhonebook->end(); ++i)
168
int index = i->index();
170
SortedPhonebookBase::iterator j = destPhonebook->find(index);
172
if (j != destPhonebook->end())
173
{ // index present in the destPhonebook
174
if (! (*j == *i)) // overwrite if different in destination
177
cout << stringPrintf(_("updating '%s' tel# %s to new tel# %s"
180
j->telephone().c_str(),
181
i->telephone().c_str(), i->index())
190
// delete those entries from destPhonebook, that are not present
191
// in sourcePhonebook
193
void deleteNotPresent(SortedPhonebookRef sourcePhonebook,
194
SortedPhonebookRef destPhonebook,
195
bool indexed, bool verbose)
197
for (SortedPhonebookBase::iterator i = destPhonebook->begin();
198
i != destPhonebook->end(); ++i)
200
pair<SortedPhonebookBase::iterator, SortedPhonebookBase::iterator> range;
203
int index = i->index();
204
range = sourcePhonebook->equal_range(index);
208
string text = i->text();
209
range = sourcePhonebook->equal_range(text);
213
for (SortedPhonebookBase::iterator j = range.first;
214
j != range.second; ++j)
216
i->setUseIndex(indexed);
217
if (j->telephone() == i->telephone())
227
cout << stringPrintf(_("deleting '%s' tel# %s"),
228
i->text().c_str(), i->telephone().c_str());
230
cout << stringPrintf(_(" (index #%d)"), i->index());
233
destPhonebook->erase(i);
234
#ifdef BUGGY_MAP_ERASE
235
deleteNotPresent(sourcePhonebook, destPhonebook, indexed, verbose);
244
int main(int argc, char *argv[])
248
// handle command line options
251
string destinationBackend;
252
string sourceBackend;
254
bool doSynchronize = true;
256
SortedPhonebookRef sourcePhonebook, destPhonebook;
257
bool verbose = false;
258
bool indexed = false;
259
string initString = DEFAULT_INIT_STRING;
260
bool swHandshake = false;
262
Ref<MeTa> sourceMeTa, destMeTa;
266
while((opt = getopt_long(argc, argv, "I:p:s:d:b:cyhvViD:S:Xt:", longOpts,
284
destination = optarg;
290
destinationBackend = optarg;
293
sourceBackend = optarg;
302
doSynchronize = false;
308
doSynchronize = true;
311
cerr << argv[0] << stringPrintf(_(": version %s [compiled %s]"),
312
VERSION, __DATE__) << endl;
316
cerr << argv[0] << _(": [-b baudrate][-c][-d device or file][-h]"
318
" [-p phonebook name][-s device or file]"
320
"[-V][-y][-X]") << endl
322
<< _(" -b, --baudrate baudrate to use for device "
325
<< _(" -c, --copy copy source entries to destination")
327
<< _(" -d, --destination sets the destination device to "
329
" to, or the file to write") << endl
330
<< _(" -D, --destination-backend sets the destination backend")
332
<< _(" -h, --help prints this message") << endl
333
<< _(" -i, --index takes index positions into account")
335
<< _(" -I, --init device AT init sequence") << endl
336
<< _(" -p, --phonebook name of phonebook to use") << endl
337
<< _(" -s, --source sets the source device to connect to,\n"
338
" or the file to read") << endl
339
<< _(" -t, --charset sets the character set to use for\n"
340
" phonebook entries") << endl
341
<< _(" -S, --source-backend sets the source backend")
343
<< _(" -v, --version prints version and exits") << endl
344
<< _(" -V, --verbose print detailed progress messages")
346
<< _(" -X, --xonxoff switch on software handshake") << endl
347
<< _(" -y, --synchronize synchronize destination with source\n"
348
" entries (destination is overwritten)\n"
349
" (see gsmpb(1) for details)")
354
throw GsmException(_("unknown option"), ParameterError);
358
// check if all parameters all present
359
if (destination == "" || source == "")
360
throw GsmException(_("both source and destination must be given"),
363
// start accessing source mobile phone or file
364
if (sourceBackend != "")
366
CustomPhonebookRegistry::createPhonebook(sourceBackend, source);
367
else if (source == "-")
368
sourcePhonebook = new SortedPhonebook(true, indexed);
369
else if (isFile(source))
370
sourcePhonebook = new SortedPhonebook(source, indexed);
374
throw GsmException(_("phonebook name must be given"), ParameterError);
376
sourceMeTa = new MeTa(new
383
baudrate == "" ? DEFAULT_BAUD_RATE :
384
baudRateStrToSpeed(baudrate), initString,
387
sourceMeTa->setCharSet(charSet);
389
new SortedPhonebook(sourceMeTa->getPhonebook(phonebook));
392
// make sure destination.c_str file exists
393
if (destination != "")
397
ofstream f(destination.c_str(), ios::out | ios::app);
404
// start accessing destination mobile phone or file
405
if (destinationBackend != "")
407
CustomPhonebookRegistry::createPhonebook(destinationBackend,
409
else if (destination == "-")
410
destPhonebook = new SortedPhonebook(false, indexed);
411
else if (isFile(destination))
412
destPhonebook = new SortedPhonebook(destination, indexed);
416
throw GsmException(_("phonebook name must be given"), ParameterError);
418
destMeTa = new MeTa(new
425
baudrate == "" ? DEFAULT_BAUD_RATE :
426
baudRateStrToSpeed(baudrate), initString,
429
destMeTa->setCharSet(charSet);
430
PhonebookRef destPb = destMeTa->getPhonebook(phonebook);
432
// check maximum lengths of source text and phonenumber when writing to
434
unsigned int maxTextLen = destPb->getMaxTextLen();
435
unsigned int maxTelLen = destPb->getMaxTelephoneLen();
437
for (SortedPhonebookBase::iterator i = sourcePhonebook->begin();
438
i != sourcePhonebook->end(); ++i)
439
if (i->text().length() > maxTextLen)
441
stringPrintf(_("text '%s' is too large to fit into destination "
442
"(maximum size %d characters)"),
443
i->text().c_str(), maxTextLen),
445
else if (i->telephone().length() > maxTelLen)
447
stringPrintf(_("phone number '%s' is too large to fit into "
448
"destination (maximum size %d characters)"),
449
i->telephone().c_str(), maxTelLen),
453
destPhonebook = new SortedPhonebook(destPb);
456
// now do the actual work
461
sourcePhonebook->setSortOrder(ByIndex);
462
destPhonebook->setSortOrder(ByIndex);
463
// for an explanation see below
464
updateEntriesIndexed(sourcePhonebook, destPhonebook, verbose);
465
deleteNotPresent(sourcePhonebook, destPhonebook, true, verbose);
466
insertNotPresent(sourcePhonebook, destPhonebook, true, verbose);
470
sourcePhonebook->setSortOrder(ByText);
471
destPhonebook->setSortOrder(ByText);
472
// the following is done to avoid superfluous writes to the TA
473
// (that takes time) and keep updated (ie. telephone number changed)
474
// entries at the same place
475
// 1. update entries in place where just the number changed
476
updateEntries(sourcePhonebook, destPhonebook, verbose);
477
// 2. delete those that are not present anymore
478
deleteNotPresent(sourcePhonebook, destPhonebook, false, verbose);
479
// 3. insert the new ones
480
insertNotPresent(sourcePhonebook, destPhonebook, false, verbose);
485
destPhonebook->clear();
486
for (SortedPhonebookBase::iterator i = sourcePhonebook->begin();
487
i != sourcePhonebook->end(); ++i)
491
cout << stringPrintf(_("inserting '%s' tel# %s"),
492
i->text().c_str(), i->telephone().c_str());
494
cout << stringPrintf(_(" (index #%d)"), i->index());
497
destPhonebook->insert(*i);
501
catch (GsmException &ge)
503
cerr << argv[0] << _("[ERROR]: ") << ge.what() << endl;