~ubuntu-branches/ubuntu/intrepid/gsmlib/intrepid

« back to all changes in this revision

Viewing changes to apps/gsmpb.cc

  • Committer: Bazaar Package Importer
  • Author(s): Mikael Hedin
  • Date: 2002-01-24 12:59:07 UTC
  • Revision ID: james.westby@ubuntu.com-20020124125907-b7qkpokx5283jdpu
Tags: upstream-1.8
ImportĀ upstreamĀ versionĀ 1.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// *************************************************************************
 
2
// * GSM TA/ME library
 
3
// *
 
4
// * File:    gsmpb.cc
 
5
// *
 
6
// * Purpose: phonebook management program
 
7
// *
 
8
// * Author:  Peter Hofmann (software@pxh.de)
 
9
// *
 
10
// * Created: 24.6.1999
 
11
// *************************************************************************
 
12
 
 
13
#ifdef HAVE_CONFIG_H
 
14
#include <gsm_config.h>
 
15
#endif
 
16
#include <gsmlib/gsm_nls.h>
 
17
#include <string>
 
18
#ifdef WIN32
 
19
#include <gsmlib/gsm_win32_serial.h>
 
20
#else
 
21
#include <gsmlib/gsm_unix_serial.h>
 
22
#include <unistd.h>
 
23
#endif
 
24
#if defined(HAVE_GETOPT_LONG) || defined(WIN32)
 
25
#include <getopt.h>
 
26
#endif
 
27
#include <stdio.h>
 
28
#include <stdlib.h>
 
29
#include <errno.h>
 
30
#include <gsmlib/gsm_me_ta.h>
 
31
#include <gsmlib/gsm_util.h>
 
32
#include <gsmlib/gsm_sorted_phonebook.h>
 
33
#include <iostream>
 
34
 
 
35
using namespace std;
 
36
using namespace gsmlib;
 
37
 
 
38
#ifdef HAVE_GETOPT_LONG
 
39
static struct option longOpts[] =
 
40
{
 
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}
 
57
};
 
58
#else
 
59
#define getopt_long(argc, argv, options, longopts, indexptr) \
 
60
  getopt(argc, argv, options)
 
61
#endif
 
62
 
 
63
// insert those entries from sourcePhonebook into destPhonebook
 
64
// that are not already present in destPhonebook
 
65
 
 
66
void insertNotPresent(SortedPhonebookRef sourcePhonebook,
 
67
                      SortedPhonebookRef destPhonebook,
 
68
                      bool indexed, bool verbose)
 
69
{
 
70
  for (SortedPhonebookBase::iterator i = sourcePhonebook->begin();
 
71
       i != sourcePhonebook->end(); ++i)
 
72
  {
 
73
    pair<SortedPhonebookBase::iterator, SortedPhonebookBase::iterator> range;
 
74
    if (indexed)
 
75
    {
 
76
      int index = i->index();
 
77
      range = destPhonebook->equal_range(index);
 
78
    }
 
79
    else
 
80
    {
 
81
      string text = i->text();
 
82
      range = destPhonebook->equal_range(text);
 
83
    }
 
84
 
 
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)
 
89
    {
 
90
      i->setUseIndex(indexed);
 
91
      if (i->telephone() == j->telephone())
 
92
      {
 
93
        alreadyPresent = true;
 
94
        break;
 
95
      }
 
96
    }
 
97
    // ... else insert it
 
98
    if (! alreadyPresent)
 
99
    {
 
100
      if (verbose)
 
101
      {
 
102
        cout << stringPrintf(_("inserting '%s' tel# %s"),
 
103
                             i->text().c_str(), i->telephone().c_str());
 
104
        if (indexed)
 
105
          cout << stringPrintf(_(" (index #%d)"), i->index());
 
106
        cout << endl;
 
107
      }
 
108
      i->setUseIndex(indexed);
 
109
      destPhonebook->insert(*i); // insert
 
110
    }
 
111
  }
 
112
}
 
113
 
 
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
 
120
 
 
121
void updateEntries(SortedPhonebookRef sourcePhonebook,
 
122
                   SortedPhonebookRef destPhonebook,
 
123
                   bool verbose)
 
124
{
 
125
  bool firstLoop = true;
 
126
  string lastText;
 
127
 
 
128
  for (SortedPhonebookBase::iterator i = sourcePhonebook->begin();
 
129
       i != sourcePhonebook->end(); ++i)
 
130
  {
 
131
    string text = i->text();
 
132
    if (! firstLoop && text != lastText)
 
133
    {
 
134
      pair<SortedPhonebookBase::iterator,
 
135
        SortedPhonebookBase::iterator> range =
 
136
        destPhonebook->equal_range(text);
 
137
      
 
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
 
142
        {
 
143
          if (verbose)
 
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())
 
148
                 << endl;
 
149
          
 
150
          *range.first = *i;
 
151
        }
 
152
      }
 
153
      lastText = text;
 
154
    }
 
155
    firstLoop = false;
 
156
  }
 
157
}
 
158
 
 
159
// the same but for indexed phonebooks
 
160
 
 
161
void updateEntriesIndexed(SortedPhonebookRef sourcePhonebook,
 
162
                          SortedPhonebookRef destPhonebook,
 
163
                          bool verbose)
 
164
{
 
165
  for (SortedPhonebookBase::iterator i = sourcePhonebook->begin();
 
166
       i != sourcePhonebook->end(); ++i)
 
167
  {
 
168
    int index = i->index();
 
169
    
 
170
    SortedPhonebookBase::iterator j = destPhonebook->find(index);
 
171
    
 
172
    if (j != destPhonebook->end())
 
173
    {                           // index present in the destPhonebook
 
174
      if (! (*j == *i))         // overwrite if different in destination
 
175
      {
 
176
        if (verbose)
 
177
          cout << stringPrintf(_("updating '%s' tel# %s to new tel# %s"
 
178
                                 "(index %d)"),
 
179
                               j->text().c_str(),
 
180
                               j->telephone().c_str(),
 
181
                               i->telephone().c_str(), i->index())
 
182
               << endl;
 
183
        
 
184
        *j = *i;
 
185
      }
 
186
    }
 
187
  }
 
188
}
 
189
 
 
190
// delete those entries from destPhonebook, that are not present
 
191
// in sourcePhonebook
 
192
 
 
193
void deleteNotPresent(SortedPhonebookRef sourcePhonebook,
 
194
                      SortedPhonebookRef destPhonebook,
 
195
                      bool indexed, bool verbose)
 
196
{
 
197
  for (SortedPhonebookBase::iterator i = destPhonebook->begin();
 
198
       i != destPhonebook->end(); ++i)
 
199
  {
 
200
    pair<SortedPhonebookBase::iterator, SortedPhonebookBase::iterator> range;
 
201
    if (indexed)
 
202
    {
 
203
      int index = i->index();
 
204
      range = sourcePhonebook->equal_range(index);
 
205
    }
 
206
    else
 
207
    {
 
208
      string text = i->text();
 
209
      range = sourcePhonebook->equal_range(text);
 
210
    }
 
211
        
 
212
    bool found = false;
 
213
    for (SortedPhonebookBase::iterator j = range.first;
 
214
         j != range.second; ++j)
 
215
    {
 
216
      i->setUseIndex(indexed);
 
217
      if (j->telephone() == i->telephone())
 
218
      {
 
219
        found = true;
 
220
        break;
 
221
      }
 
222
    }
 
223
    if (! found)
 
224
    {
 
225
      if (verbose)
 
226
      {
 
227
        cout << stringPrintf(_("deleting '%s' tel# %s"),
 
228
                             i->text().c_str(), i->telephone().c_str());
 
229
        if (indexed)
 
230
          cout << stringPrintf(_(" (index #%d)"), i->index());
 
231
        cout << endl;
 
232
      }
 
233
      destPhonebook->erase(i);
 
234
#ifdef BUGGY_MAP_ERASE
 
235
          deleteNotPresent(sourcePhonebook, destPhonebook, indexed, verbose);
 
236
          return;
 
237
#endif
 
238
    }
 
239
  }
 
240
}
 
241
 
 
242
// *** main program
 
243
 
 
244
int main(int argc, char *argv[])
 
245
{
 
246
  try
 
247
  {
 
248
    // handle command line options
 
249
    string destination;
 
250
    string source;
 
251
    string destinationBackend;
 
252
    string sourceBackend;
 
253
    string baudrate;
 
254
    bool doSynchronize = true;
 
255
    string phonebook;
 
256
    SortedPhonebookRef sourcePhonebook, destPhonebook;
 
257
    bool verbose = false;
 
258
    bool indexed = false;
 
259
    string initString = DEFAULT_INIT_STRING;
 
260
    bool swHandshake = false;
 
261
    string charSet;
 
262
    Ref<MeTa> sourceMeTa, destMeTa;
 
263
 
 
264
    int opt;
 
265
    int dummy;
 
266
    while((opt = getopt_long(argc, argv, "I:p:s:d:b:cyhvViD:S:Xt:", longOpts,
 
267
                             &dummy))
 
268
          != -1)
 
269
      switch (opt)
 
270
      {
 
271
      case 'X':
 
272
        swHandshake = true;
 
273
        break;
 
274
      case 'I':
 
275
        initString = optarg;
 
276
        break;
 
277
      case 'V':
 
278
        verbose = true;
 
279
        break;
 
280
      case 'p':
 
281
        phonebook = optarg;
 
282
        break;
 
283
      case 'd':
 
284
        destination = optarg;
 
285
        break;
 
286
      case 's':
 
287
        source = optarg;
 
288
        break;
 
289
      case 'D':
 
290
        destinationBackend = optarg;
 
291
        break;
 
292
      case 'S':
 
293
        sourceBackend = optarg;
 
294
        break;
 
295
      case 'b':
 
296
        baudrate = optarg;
 
297
        break;
 
298
      case 't':
 
299
        charSet = optarg;
 
300
        break;
 
301
      case 'c':
 
302
        doSynchronize = false;
 
303
        break;
 
304
      case 'i':
 
305
        indexed = true;
 
306
        break;
 
307
      case 'y':
 
308
        doSynchronize = true;
 
309
        break;
 
310
      case 'v':
 
311
        cerr << argv[0] << stringPrintf(_(": version %s [compiled %s]"),
 
312
                                        VERSION, __DATE__) << endl;
 
313
        exit(0);
 
314
        break;
 
315
      case 'h':
 
316
        cerr << argv[0] << _(": [-b baudrate][-c][-d device or file][-h]"
 
317
                             "[-I init string]\n"
 
318
                             "  [-p phonebook name][-s device or file]"
 
319
                             "[-t charset][-v]"
 
320
                             "[-V][-y][-X]") << endl
 
321
             << endl
 
322
             << _("  -b, --baudrate    baudrate to use for device "
 
323
                  "(default: 38400)")
 
324
             << endl
 
325
             << _("  -c, --copy        copy source entries to destination")
 
326
             << endl
 
327
             << _("  -d, --destination sets the destination device to "
 
328
                  "connect \n"
 
329
                  "                    to, or the file to write") << endl
 
330
             << _("  -D, --destination-backend sets the destination backend")
 
331
             << endl
 
332
             << _("  -h, --help        prints this message") << endl
 
333
             << _("  -i, --index       takes index positions into account")
 
334
             << endl
 
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")
 
342
             << endl
 
343
             << _("  -v, --version     prints version and exits") << endl
 
344
             << _("  -V, --verbose     print detailed progress messages")
 
345
             << endl
 
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)")
 
350
             << endl << endl;
 
351
        exit(0);
 
352
        break;
 
353
      case '?':
 
354
        throw GsmException(_("unknown option"), ParameterError);
 
355
        break;
 
356
      }
 
357
 
 
358
    // check if all parameters all present
 
359
    if (destination == "" || source == "")
 
360
      throw GsmException(_("both source and destination must be given"),
 
361
                         ParameterError);
 
362
 
 
363
    // start accessing source mobile phone or file
 
364
    if (sourceBackend != "")
 
365
      sourcePhonebook =
 
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);
 
371
    else
 
372
    {
 
373
      if (phonebook == "")
 
374
        throw GsmException(_("phonebook name must be given"), ParameterError);
 
375
 
 
376
      sourceMeTa = new MeTa(new
 
377
#ifdef WIN32
 
378
                            Win32SerialPort
 
379
#else
 
380
                            UnixSerialPort
 
381
#endif
 
382
                            (source,
 
383
                             baudrate == "" ? DEFAULT_BAUD_RATE :
 
384
                             baudRateStrToSpeed(baudrate), initString,
 
385
                             swHandshake));
 
386
      if (charSet != "")
 
387
        sourceMeTa->setCharSet(charSet);
 
388
      sourcePhonebook =
 
389
        new SortedPhonebook(sourceMeTa->getPhonebook(phonebook));
 
390
    }
 
391
 
 
392
    // make sure destination.c_str file exists
 
393
        if (destination != "")
 
394
        {
 
395
      try
 
396
          {
 
397
        ofstream f(destination.c_str(), ios::out | ios::app);
 
398
          }
 
399
      catch (exception)
 
400
          {
 
401
          }
 
402
        }
 
403
 
 
404
    // start accessing destination mobile phone or file
 
405
    if (destinationBackend != "")
 
406
      destPhonebook =
 
407
        CustomPhonebookRegistry::createPhonebook(destinationBackend,
 
408
                                                 destination);
 
409
    else if (destination == "-")
 
410
      destPhonebook = new SortedPhonebook(false, indexed);
 
411
    else if (isFile(destination))
 
412
      destPhonebook = new SortedPhonebook(destination, indexed);
 
413
    else
 
414
    {
 
415
      if (phonebook == "")
 
416
        throw GsmException(_("phonebook name must be given"), ParameterError);
 
417
 
 
418
      destMeTa = new MeTa(new 
 
419
#ifdef WIN32
 
420
                          Win32SerialPort
 
421
#else
 
422
                          UnixSerialPort
 
423
#endif
 
424
                          (destination,
 
425
                           baudrate == "" ? DEFAULT_BAUD_RATE :
 
426
                           baudRateStrToSpeed(baudrate), initString,
 
427
                           swHandshake));
 
428
      if (charSet != "")
 
429
        destMeTa->setCharSet(charSet);
 
430
      PhonebookRef destPb = destMeTa->getPhonebook(phonebook);
 
431
 
 
432
      // check maximum lengths of source text and phonenumber when writing to
 
433
      // mobile phone
 
434
      unsigned int maxTextLen = destPb->getMaxTextLen();
 
435
      unsigned int maxTelLen = destPb->getMaxTelephoneLen();
 
436
 
 
437
      for (SortedPhonebookBase::iterator i = sourcePhonebook->begin();
 
438
           i != sourcePhonebook->end(); ++i)
 
439
        if (i->text().length() > maxTextLen)
 
440
          throw GsmException(
 
441
            stringPrintf(_("text '%s' is too large to fit into destination "
 
442
                           "(maximum size %d characters)"),
 
443
                         i->text().c_str(), maxTextLen),
 
444
            ParameterError);
 
445
        else if (i->telephone().length() > maxTelLen)
 
446
          throw GsmException(
 
447
            stringPrintf(_("phone number '%s' is too large to fit into "
 
448
                           "destination (maximum size %d characters)"),
 
449
                         i->telephone().c_str(), maxTelLen),
 
450
            ParameterError);
 
451
 
 
452
      // read phonebook
 
453
      destPhonebook = new SortedPhonebook(destPb);      
 
454
    }
 
455
 
 
456
    // now do the actual work
 
457
    if (doSynchronize)
 
458
    {                           // synchronizing
 
459
      if (indexed)
 
460
      {
 
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);
 
467
      }
 
468
      else
 
469
      {
 
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);
 
481
      }
 
482
    }
 
483
    else
 
484
    {                           // copying
 
485
      destPhonebook->clear();
 
486
      for (SortedPhonebookBase::iterator i = sourcePhonebook->begin();
 
487
           i != sourcePhonebook->end(); ++i)
 
488
      {
 
489
        if (verbose)
 
490
        {
 
491
          cout << stringPrintf(_("inserting '%s' tel# %s"),
 
492
                               i->text().c_str(), i->telephone().c_str());
 
493
          if (indexed)
 
494
            cout << stringPrintf(_(" (index #%d)"), i->index());
 
495
          cout << endl;
 
496
        }
 
497
        destPhonebook->insert(*i);
 
498
      }
 
499
    }
 
500
  }
 
501
  catch (GsmException &ge)
 
502
  {
 
503
    cerr << argv[0] << _("[ERROR]: ") << ge.what() << endl;
 
504
    return 1;
 
505
  }
 
506
  return 0;
 
507
}