1 //indent -gnu -ts4 -br -brs -cdw -lp -ce -nbfda -npcs -nprs -npsl -nbbo -saf -sai -saw -cs -bbo -nhnl -nut -sob -l90
2 #include "celliax.h"
3 #include "iconv.h"
4 
5 extern int celliax_debug;
6 extern char *celliax_console_active;
7 extern char celliax_type[];
8 extern struct celliax_pvt *celliax_iflist;
9 extern int celliax_dir_entry_extension;
10 
11 #ifndef GIOVA48
12 #define SAMPLES_PER_FRAME 160
13 #else // GIOVA48
14 #define SAMPLES_PER_FRAME 960
15 #endif // GIOVA48
16 
17 #ifdef CELLIAX_ALSA
18 /*! \brief ALSA pcm format, according to endianess  */
19 #if __BYTE_ORDER == __LITTLE_ENDIAN
20 snd_pcm_format_t celliax_format = SND_PCM_FORMAT_S16_LE;
21 #else
22 snd_pcm_format_t celliax_format = SND_PCM_FORMAT_S16_BE;
23 #endif
24 
25 /*!
26  * \brief Initialize the ALSA soundcard channels (capture AND playback) used by one interface (a multichannel soundcard can be used by multiple interfaces)
27  * \param p the celliax_pvt of the interface
28  *
29  * This function call alsa_open_dev to initialize the ALSA soundcard for each channel (capture AND playback) used by one interface (a multichannel soundcard can be used by multiple interfaces). Called by sound_init
30  *
31  * \return zero on success, -1 on error.
32  */
alsa_init(struct celliax_pvt * p)33 int alsa_init(struct celliax_pvt *p)
34 {
35   p->alsac = alsa_open_dev(p, SND_PCM_STREAM_CAPTURE);
36   if (!p->alsac) {
37     ERRORA("Failed opening ALSA capture device: %s\n", CELLIAX_P_LOG, p->alsacname);
38     if (alsa_shutdown(p)) {
39       ERRORA("alsa_shutdown failed\n", CELLIAX_P_LOG);
40       return -1;
41     }
42     return -1;
43   }
44   p->alsap = alsa_open_dev(p, SND_PCM_STREAM_PLAYBACK);
45   if (!p->alsap) {
46     ERRORA("Failed opening ALSA playback device: %s\n", CELLIAX_P_LOG, p->alsapname);
47     if (alsa_shutdown(p)) {
48       ERRORA("alsa_shutdown failed\n", CELLIAX_P_LOG);
49       return -1;
50     }
51     return -1;
52   }
53 
54   /* make valgrind very happy */
55   snd_config_update_free_global();
56   return 0;
57 }
58 
59 /*!
60  * \brief Shutdown the ALSA soundcard channels (input and output) used by one interface (a multichannel soundcard can be used by multiple interfaces)
61  * \param p the celliax_pvt of the interface
62  *
63  * This function shutdown the ALSA soundcard channels (input and output) used by one interface (a multichannel soundcard can be used by multiple interfaces). Called by sound_init
64  *
65  * \return zero on success, -1 on error.
66  */
67 
alsa_shutdown(struct celliax_pvt * p)68 int alsa_shutdown(struct celliax_pvt *p)
69 {
70 
71   int err;
72 
73   if (p->alsap) {
74     err = snd_pcm_drop(p->alsap);
75     if (err < 0) {
76       ERRORA("device [%s], snd_pcm_drop failed with error '%s'\n", CELLIAX_P_LOG,
77              p->alsapname, snd_strerror(err));
78       return -1;
79     }
80     err = snd_pcm_close(p->alsap);
81     if (err < 0) {
82       ERRORA("device [%s], snd_pcm_close failed with error '%s'\n", CELLIAX_P_LOG,
83              p->alsapname, snd_strerror(err));
84       return -1;
85     }
86   }
87   if (p->alsac) {
88     err = snd_pcm_drop(p->alsac);
89     if (err < 0) {
90       ERRORA("device [%s], snd_pcm_drop failed with error '%s'\n", CELLIAX_P_LOG,
91              p->alsacname, snd_strerror(err));
92       return -1;
93     }
94     err = snd_pcm_close(p->alsac);
95     if (err < 0) {
96       ERRORA("device [%s], snd_pcm_close failed with error '%s'\n", CELLIAX_P_LOG,
97              p->alsacname, snd_strerror(err));
98       return -1;
99     }
100   }
101 
102   return 0;
103 }
104 
105 /*!
106  * \brief Setup and open the ALSA device (capture OR playback)
107  * \param p the celliax_pvt of the interface
108  * \param stream the ALSA capture/playback definition
109  *
110  * This function setup and open the ALSA device (capture OR playback). Called by alsa_init
111  *
112  * \return zero on success, -1 on error.
113  */
alsa_open_dev(struct celliax_pvt * p,snd_pcm_stream_t stream)114 snd_pcm_t *alsa_open_dev(struct celliax_pvt * p, snd_pcm_stream_t stream)
115 {
116 
117   snd_pcm_t *handle = NULL;
118   snd_pcm_hw_params_t *params;
119   snd_pcm_sw_params_t *swparams;
120   snd_pcm_uframes_t buffer_size;
121   int err;
122   size_t n;
123   //snd_pcm_uframes_t xfer_align;
124   unsigned int rate;
125   snd_pcm_uframes_t start_threshold, stop_threshold;
126   snd_pcm_uframes_t period_size = 0;
127   snd_pcm_uframes_t chunk_size = 0;
128   int start_delay = 0;
129   int stop_delay = 0;
130   snd_pcm_state_t state;
131   snd_pcm_info_t *info;
132 
133   period_size = p->alsa_period_size;
134 
135   snd_pcm_hw_params_alloca(&params);
136   snd_pcm_sw_params_alloca(&swparams);
137 
138   if (stream == SND_PCM_STREAM_CAPTURE) {
139     err = snd_pcm_open(&handle, p->alsacname, stream, 0 | SND_PCM_NONBLOCK);
140   } else {
141     err = snd_pcm_open(&handle, p->alsapname, stream, 0 | SND_PCM_NONBLOCK);
142   }
143   if (err < 0) {
144     ERRORA
145       ("snd_pcm_open failed with error '%s' on device '%s', if you are using a plughw:n device please change it to be a default:n device (so to allow it to be shared with other concurrent programs), or maybe you are using an ALSA voicemodem and slmodemd"
146        " is running?\n", CELLIAX_P_LOG, snd_strerror(err),
147        stream == SND_PCM_STREAM_CAPTURE ? p->alsacname : p->alsapname);
148     return NULL;
149   }
150 
151   snd_pcm_info_alloca(&info);
152 
153   if ((err = snd_pcm_info(handle, info)) < 0) {
154     ERRORA("info error: %s", CELLIAX_P_LOG, snd_strerror(err));
155     return NULL;
156   }
157 
158   err = snd_pcm_nonblock(handle, 1);
159   if (err < 0) {
160     ERRORA("nonblock setting error: %s", CELLIAX_P_LOG, snd_strerror(err));
161     return NULL;
162   }
163 
164   err = snd_pcm_hw_params_any(handle, params);
165   if (err < 0) {
166     ERRORA("Broken configuration for this PCM, no configurations available: %s\n",
167            CELLIAX_P_LOG, snd_strerror(err));
168     return NULL;
169   }
170 
171   err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
172   if (err < 0) {
173     ERRORA("Access type not available: %s\n", CELLIAX_P_LOG, snd_strerror(err));
174     return NULL;
175   }
176   err = snd_pcm_hw_params_set_format(handle, params, celliax_format);
177   if (err < 0) {
178     ERRORA("Sample format non available: %s\n", CELLIAX_P_LOG, snd_strerror(err));
179     return NULL;
180   }
181   err = snd_pcm_hw_params_set_channels(handle, params, 1);
182   if (err < 0) {
183     DEBUGA_SOUND("Channels count set failed: %s\n", CELLIAX_P_LOG, snd_strerror(err));
184   }
185 #if 1
186   unsigned int chan_num;
187   err = snd_pcm_hw_params_get_channels(params, &chan_num);
188   if (err < 0) {
189     ERRORA("Channels count non available: %s\n", CELLIAX_P_LOG, snd_strerror(err));
190     return NULL;
191   }
192   if (chan_num < 1 || chan_num > 2) {
193     ERRORA("Channels count MUST BE 1 or 2, it is: %d\n", CELLIAX_P_LOG, chan_num);
194     ERRORA("Channels count MUST BE 1 or 2, it is: %d on %s %s\n", CELLIAX_P_LOG, chan_num,
195            p->alsapname, p->alsacname);
196     return NULL;
197   } else {
198     if (chan_num == 1) {
199       if (stream == SND_PCM_STREAM_CAPTURE)
200         p->alsa_capture_is_mono = 1;
201       else
202         p->alsa_play_is_mono = 1;
203     } else {
204       if (stream == SND_PCM_STREAM_CAPTURE)
205         p->alsa_capture_is_mono = 0;
206       else
207         p->alsa_play_is_mono = 0;
208     }
209   }
210 #else
211   p->alsa_capture_is_mono = 1;
212   p->alsa_play_is_mono = 1;
213 #endif
214 
215 #if 0
216   unsigned int buffer_time = 0;
217   unsigned int period_time = 0;
218   snd_pcm_uframes_t period_frames = 0;
219   snd_pcm_uframes_t buffer_frames = 0;
220 
221   if (buffer_time == 0 && buffer_frames == 0) {
222     err = snd_pcm_hw_params_get_buffer_time_max(params, &buffer_time, 0);
223     assert(err >= 0);
224     if (buffer_time > 500000)
225       buffer_time = 500000;
226   }
227   if (period_time == 0 && period_frames == 0) {
228     if (buffer_time > 0)
229       period_time = buffer_time / 4;
230     else
231       period_frames = buffer_frames / 4;
232   }
233   if (period_time > 0)
234     err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, 0);
235   else
236     err = snd_pcm_hw_params_set_period_size_near(handle, params, &period_frames, 0);
237   assert(err >= 0);
238   if (buffer_time > 0) {
239     err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, 0);
240   } else {
241     err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_frames);
242   }
243 #endif
244 
245 #if 1
246   rate = p->celliax_sound_rate;
247   err = snd_pcm_hw_params_set_rate_near(handle, params, &rate, 0);
248   if ((float) p->celliax_sound_rate * 1.05 < rate
249       || (float) p->celliax_sound_rate * 0.95 > rate) {
250     WARNINGA("Rate is not accurate (requested = %iHz, got = %iHz)\n", CELLIAX_P_LOG,
251              p->celliax_sound_rate, rate);
252   }
253 
254   if (err < 0) {
255     ERRORA("Error setting rate: %s\n", CELLIAX_P_LOG, snd_strerror(err));
256     return NULL;
257   }
258   p->celliax_sound_rate = rate;
259 
260   err = snd_pcm_hw_params_set_period_size_near(handle, params, &period_size, 0);
261 
262   if (err < 0) {
263     ERRORA("Error setting period_size: %s\n", CELLIAX_P_LOG, snd_strerror(err));
264     return NULL;
265   }
266 
267   p->alsa_period_size = period_size;
268 
269   p->alsa_buffer_size = p->alsa_period_size * p->alsa_periods_in_buffer;
270 
271   err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &p->alsa_buffer_size);
272 
273   if (err < 0) {
274     ERRORA("Error setting buffer_size: %s\n", CELLIAX_P_LOG, snd_strerror(err));
275     return NULL;
276   }
277 #endif
278 
279   err = snd_pcm_hw_params(handle, params);
280   if (err < 0) {
281     ERRORA("Unable to install hw params: %s\n", CELLIAX_P_LOG, snd_strerror(err));
282     return NULL;
283   }
284 
285   snd_pcm_hw_params_get_period_size(params, &chunk_size, 0);
286   snd_pcm_hw_params_get_buffer_size(params, &buffer_size);
287   if (chunk_size == buffer_size) {
288     ERRORA("Can't use period equal to buffer size (%lu == %lu)\n", CELLIAX_P_LOG,
289            chunk_size, buffer_size);
290     return NULL;
291   }
292 
293   snd_pcm_sw_params_current(handle, swparams);
294 
295 #if 0
296   err = snd_pcm_sw_params_get_xfer_align(swparams, &xfer_align);
297   if (err < 0) {
298     ERRORA("Unable to obtain xfer align: %s\n", CELLIAX_P_LOG, snd_strerror(err));
299   }
300   NOTICA("xfer_align: %d\n", CELLIAX_P_LOG, xfer_align);
301   /* for some reason, on some platforms, xfer_align here is zero, that gives a floating point exception later. So, let's try to force it to 160, the frame size used by celliax */
302   xfer_align = p->alsa_period_size;
303   NOTICA("xfer_align: %d\n", CELLIAX_P_LOG, xfer_align);
304 
305   err = snd_pcm_sw_params_set_xfer_align(handle, swparams, xfer_align);
306   if (err < 0) {
307     ERRORA("Error setting xfer_align: %s\n", CELLIAX_P_LOG, snd_strerror(err));
308   }
309   NOTICA("xfer_align: %d\n", CELLIAX_P_LOG, xfer_align);
310 
311   err = snd_pcm_sw_params_get_xfer_align(swparams, &xfer_align);
312   if (err < 0) {
313     ERRORA("Unable to obtain xfer align: %s\n", CELLIAX_P_LOG, snd_strerror(err));
314   }
315   NOTICA("xfer_align: %d\n", CELLIAX_P_LOG, xfer_align);
316 #endif
317 
318   /*
319      if (sleep_min)
320      xfer_align = 1;
321      err = snd_pcm_sw_params_set_sleep_min(handle, swparams,
322      0);
323 
324      if (err < 0) {
325      ERRORA("Error setting slep_min: %s\n", CELLIAX_P_LOG, snd_strerror(err));
326      }
327    */
328   n = chunk_size;
329   err = snd_pcm_sw_params_set_avail_min(handle, swparams, n);
330   if (err < 0) {
331     ERRORA("Error setting avail_min: %s\n", CELLIAX_P_LOG, snd_strerror(err));
332   }
333 #if 0
334   /* round up to closest transfer boundary */
335   if (xfer_align == 0) {        //so to avoid floating point exception ????
336     xfer_align = 160;
337   }
338   //original n = (buffer_size / xfer_align) * xfer_align;
339   n = (chunk_size / xfer_align) * xfer_align;
340 #endif
341   if (stream == SND_PCM_STREAM_CAPTURE) {
342     start_delay = 1;
343   }
344   if (start_delay <= 0) {
345     start_threshold = n + (double) rate *start_delay / 1000000;
346   } else {
347     start_threshold = (double) rate *start_delay / 1000000;
348   }
349   if (start_threshold < 1)
350     start_threshold = 1;
351   if (start_threshold > n)
352     start_threshold = n;
353   err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
354   if (err < 0) {
355     ERRORA("Error setting start_threshold: %s\n", CELLIAX_P_LOG, snd_strerror(err));
356   }
357 
358   if (stop_delay <= 0)
359     stop_threshold = buffer_size + (double) rate *stop_delay / 1000000;
360   else
361     stop_threshold = (double) rate *stop_delay / 1000000;
362 
363   if (stream == SND_PCM_STREAM_CAPTURE) {
364     stop_threshold = -1;
365   }
366 
367   err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
368 
369   if (err < 0) {
370     ERRORA("Error setting stop_threshold: %s\n", CELLIAX_P_LOG, snd_strerror(err));
371   }
372 #if 0
373   err = snd_pcm_sw_params_set_xfer_align(handle, swparams, xfer_align);
374 
375   if (err < 0) {
376     ERRORA("Error setting xfer_align: %s\n", CELLIAX_P_LOG, snd_strerror(err));
377   }
378 #endif
379 
380   if (snd_pcm_sw_params(handle, swparams) < 0) {
381     ERRORA("Error installing software parameters: %s\n", CELLIAX_P_LOG,
382            snd_strerror(err));
383   }
384 
385   err = snd_pcm_poll_descriptors_count(handle);
386   if (err <= 0) {
387     ERRORA("Unable to get a poll descriptors count, error is %s\n", CELLIAX_P_LOG,
388            snd_strerror(err));
389     return NULL;
390   }
391 
392   if (err != 1) {               //number of poll descriptors
393     DEBUGA_SOUND("Can't handle more than one device\n", CELLIAX_P_LOG);
394     return NULL;
395   }
396 
397   err = snd_pcm_poll_descriptors(handle, &p->pfd, err);
398   if (err != 1) {
399     ERRORA("snd_pcm_poll_descriptors failed, %s\n", CELLIAX_P_LOG, snd_strerror(err));
400     return NULL;
401   }
402   DEBUGA_SOUND("Acquired fd %d from the poll descriptor\n", CELLIAX_P_LOG, p->pfd.fd);
403 
404   if (stream == SND_PCM_STREAM_CAPTURE) {
405     p->celliax_sound_capt_fd = p->pfd.fd;
406   }
407 
408   state = snd_pcm_state(handle);
409 
410   if (state != SND_PCM_STATE_RUNNING) {
411     if (state != SND_PCM_STATE_PREPARED) {
412       err = snd_pcm_prepare(handle);
413       if (err) {
414         ERRORA("snd_pcm_prepare failed, %s\n", CELLIAX_P_LOG, snd_strerror(err));
415         return NULL;
416       }
417       DEBUGA_SOUND("prepared!\n", CELLIAX_P_LOG);
418     }
419     if (stream == SND_PCM_STREAM_CAPTURE) {
420       err = snd_pcm_start(handle);
421       if (err) {
422         ERRORA("snd_pcm_start failed, %s\n", CELLIAX_P_LOG, snd_strerror(err));
423         return NULL;
424       }
425       DEBUGA_SOUND("started!\n", CELLIAX_P_LOG);
426     }
427   }
428   if (option_debug > 1) {
429     snd_output_t *output = NULL;
430     err = snd_output_stdio_attach(&output, stdout, 0);
431     if (err < 0) {
432       ERRORA("snd_output_stdio_attach failed: %s\n", CELLIAX_P_LOG, snd_strerror(err));
433     }
434     snd_pcm_dump(handle, output);
435   }
436   if (option_debug > 1)
437     DEBUGA_SOUND("ALSA handle = %ld\n", CELLIAX_P_LOG, (long int) handle);
438   return handle;
439 
440 }
441 
442 /*! \brief Read audio frames from interface */
443 
alsa_read(struct celliax_pvt * p)444 struct ast_frame *alsa_read(struct celliax_pvt *p)
445 {
446   static struct ast_frame f;
447   static short __buf[CELLIAX_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2];
448   static short __buf2[(CELLIAX_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2) * 2];
449   short *buf;
450   short *buf2;
451   static int readpos = 0;
452   static int left = CELLIAX_FRAME_SIZE;
453   snd_pcm_state_t state;
454   int r = 0;
455   int off = 0;
456   int error = 0;
457   //time_t now_timestamp;
458 
459   //memset(&f, 0, sizeof(struct ast_frame)); //giova
460 
461   f.frametype = AST_FRAME_NULL;
462   f.subclass = 0;
463   f.samples = 0;
464   f.datalen = 0;
465   f.data = NULL;
466   f.offset = 0;
467   f.src = celliax_type;
468   f.mallocd = 0;
469   f.delivery.tv_sec = 0;
470   f.delivery.tv_usec = 0;
471 
472   state = snd_pcm_state(p->alsac);
473   if (state != SND_PCM_STATE_RUNNING) {
474     DEBUGA_SOUND("ALSA read state is not SND_PCM_STATE_RUNNING\n", CELLIAX_P_LOG);
475 
476     if (state != SND_PCM_STATE_PREPARED) {
477       error = snd_pcm_prepare(p->alsac);
478       if (error) {
479         ERRORA("snd_pcm_prepare failed, %s\n", CELLIAX_P_LOG, snd_strerror(error));
480         return &f;
481       }
482       DEBUGA_SOUND("prepared!\n", CELLIAX_P_LOG);
483     }
484     usleep(1000);
485     error = snd_pcm_start(p->alsac);
486     if (error) {
487       ERRORA("snd_pcm_start failed, %s\n", CELLIAX_P_LOG, snd_strerror(error));
488       return &f;
489     }
490     DEBUGA_SOUND("started!\n", CELLIAX_P_LOG);
491     usleep(1000);
492   }
493 
494   buf = __buf + AST_FRIENDLY_OFFSET / 2;
495   buf2 = __buf2 + ((AST_FRIENDLY_OFFSET / 2) * 2);
496 
497   if (p->alsa_capture_is_mono) {
498     r = snd_pcm_readi(p->alsac, buf + readpos, left);
499   } else {
500     r = snd_pcm_readi(p->alsac, buf2 + (readpos * 2), left);
501 
502     int a = 0;
503     int i = 0;
504     for (i = 0; i < (CELLIAX_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2) * 2;) {
505       __buf[a] = (__buf2[i] + __buf2[i + 1]) / 2;   //comment out this line to use only left
506       //__buf[a] = __buf2[i]; // enable this line to use only left
507       a++;
508       i++;
509       i++;
510     }
511   }
512 
513   if (r == -EPIPE) {
514     ERRORA("XRUN read\n\n\n\n\n", CELLIAX_P_LOG);
515     return &f;
516   } else if (r == -ESTRPIPE) {
517     ERRORA("-ESTRPIPE\n", CELLIAX_P_LOG);
518     return &f;
519 
520   } else if (r == -EAGAIN) {
521     DEBUGA_SOUND("ALSA read -EAGAIN, the soundcard is not ready to be read by celliax\n",
522                  CELLIAX_P_LOG);
523     while (r == -EAGAIN) {
524       usleep(1000);
525 
526       if (p->alsa_capture_is_mono) {
527         r = snd_pcm_readi(p->alsac, buf + readpos, left);
528       } else {
529         r = snd_pcm_readi(p->alsac, buf2 + (readpos * 2), left);
530 
531         int a = 0;
532         int i = 0;
533         for (i = 0; i < (CELLIAX_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2) * 2;) {
534           __buf[a] = (__buf2[i] + __buf2[i + 1]) / 2;
535           a++;
536           i++;
537           i++;
538         }
539       }
540 
541     }
542   } else if (r < 0) {
543     WARNINGA("ALSA Read error: %s\n", CELLIAX_P_LOG, snd_strerror(r));
544   } else if (r >= 0) {
545     //DEBUGA_SOUND("read: r=%d, readpos=%d, left=%d, off=%d\n", CELLIAX_P_LOG, r, readpos, left, off);
546     off -= r;                   //what is the meaning of this? a leftover, probably
547   }
548   /* Update positions */
549   readpos += r;
550   left -= r;
551 
552   if (readpos >= CELLIAX_FRAME_SIZE) {
553     /* A real frame */
554     readpos = 0;
555     left = CELLIAX_FRAME_SIZE;
556 
557     f.frametype = AST_FRAME_VOICE;
558     f.subclass = AST_FORMAT_SLINEAR;
559     f.samples = CELLIAX_FRAME_SIZE;
560     f.datalen = CELLIAX_FRAME_SIZE * 2;
561     f.data = buf;
562     f.offset = AST_FRIENDLY_OFFSET;
563     f.src = celliax_type;
564     f.mallocd = 0;
565 #ifdef ALSA_MONITOR
566     alsa_monitor_read((char *) buf, CELLIAX_FRAME_SIZE * 2);
567 #endif
568 
569   }
570   return &f;
571 }
572 
573 /*! \brief Write audio frames to interface */
alsa_write(struct celliax_pvt * p,struct ast_frame * f)574 int alsa_write(struct celliax_pvt *p, struct ast_frame *f)
575 {
576   static char sizbuf[8000];
577   static char sizbuf2[16000];
578   static char silencebuf[8000];
579   static int sizpos = 0;
580   int len = sizpos;
581   int pos;
582   int res = 0;
583   time_t now_timestamp;
584   /* size_t frames = 0; */
585   snd_pcm_state_t state;
586   snd_pcm_sframes_t delayp1;
587   snd_pcm_sframes_t delayp2;
588 
589   /* We have to digest the frame in 160-byte portions */
590   if (f->datalen > sizeof(sizbuf) - sizpos) {
591     ERRORA("Frame too large\n", CELLIAX_P_LOG);
592     res = -1;
593   } else {
594     memcpy(sizbuf + sizpos, f->data, f->datalen);
595     len += f->datalen;
596     pos = 0;
597 #ifdef ALSA_MONITOR
598     alsa_monitor_write(sizbuf, len);
599 #endif
600     state = snd_pcm_state(p->alsap);
601     if (state == SND_PCM_STATE_XRUN) {
602       int i;
603 
604       DEBUGA_SOUND
605         ("You've got an ALSA write XRUN in the past (celliax can't fill the soundcard buffer fast enough). If this happens often (not after silence or after a pause in the speech, that's OK), and appear to damage the sound quality, first check if you have some IRQ problem, maybe sharing the soundcard IRQ with a broken or heavy loaded ethernet or graphic card. Then consider to increase the alsa_periods_in_buffer (now is set to %d) for this interface in the config file\n",
606          CELLIAX_P_LOG, p->alsa_periods_in_buffer);
607       res = snd_pcm_prepare(p->alsap);
608       if (res) {
609         ERRORA("audio play prepare failed: %s\n", CELLIAX_P_LOG, snd_strerror(res));
610       } else {
611         res = snd_pcm_format_set_silence(celliax_format, silencebuf, len / 2);
612         if (res < 0) {
613           DEBUGA_SOUND("Silence error %s\n", CELLIAX_P_LOG, snd_strerror(res));
614           res = -1;
615         }
616         for (i = 0; i < (p->alsa_periods_in_buffer - 1); i++) {
617           res = snd_pcm_writei(p->alsap, silencebuf, len / 2);
618           if (res != len / 2) {
619             DEBUGA_SOUND("Write returned a different quantity: %d\n", CELLIAX_P_LOG, res);
620             res = -1;
621           } else if (res < 0) {
622             DEBUGA_SOUND("Write error %s\n", CELLIAX_P_LOG, snd_strerror(res));
623             res = -1;
624           }
625         }
626       }
627 
628     }
629 
630     res = snd_pcm_delay(p->alsap, &delayp1);
631     if (res < 0) {
632       DEBUGA_SOUND("Error %d on snd_pcm_delay: \"%s\"\n", CELLIAX_P_LOG, res,
633                    snd_strerror(res));
634       res = snd_pcm_prepare(p->alsap);
635       if (res) {
636         DEBUGA_SOUND("snd_pcm_prepare failed: '%s'\n", CELLIAX_P_LOG, snd_strerror(res));
637       }
638       res = snd_pcm_delay(p->alsap, &delayp1);
639     }
640 
641     delayp2 = snd_pcm_avail_update(p->alsap);
642     if (delayp2 < 0) {
643       DEBUGA_SOUND("Error %d on snd_pcm_avail_update: \"%s\"\n", CELLIAX_P_LOG,
644                    (int) delayp2, snd_strerror(delayp2));
645 
646       res = snd_pcm_prepare(p->alsap);
647       if (res) {
648         DEBUGA_SOUND("snd_pcm_prepare failed: '%s'\n", CELLIAX_P_LOG, snd_strerror(res));
649       }
650       delayp2 = snd_pcm_avail_update(p->alsap);
651     }
652 
653     if (                        /* delayp1 != 0 && delayp1 != 160 */
654          delayp1 < 160 || delayp2 > p->alsa_buffer_size) {
655 
656       res = snd_pcm_prepare(p->alsap);
657       if (res) {
658         DEBUGA_SOUND
659           ("snd_pcm_prepare failed while trying to prevent an ALSA write XRUN: %s, delayp1=%d, delayp2=%d\n",
660            CELLIAX_P_LOG, snd_strerror(res), (int) delayp1, (int) delayp2);
661       } else {
662 
663         int i;
664         for (i = 0; i < (p->alsa_periods_in_buffer - 1); i++) {
665           res = snd_pcm_format_set_silence(celliax_format, silencebuf, len / 2);
666           if (res < 0) {
667             DEBUGA_SOUND("Silence error %s\n", CELLIAX_P_LOG, snd_strerror(res));
668             res = -1;
669           }
670           res = snd_pcm_writei(p->alsap, silencebuf, len / 2);
671           if (res < 0) {
672             DEBUGA_SOUND("Write error %s\n", CELLIAX_P_LOG, snd_strerror(res));
673             res = -1;
674           } else if (res != len / 2) {
675             DEBUGA_SOUND("Write returned a different quantity: %d\n", CELLIAX_P_LOG, res);
676             res = -1;
677           }
678         }
679 
680         DEBUGA_SOUND
681           ("PREVENTING an ALSA write XRUN (celliax can't fill the soundcard buffer fast enough). If this happens often (not after silence or after a pause in the speech, that's OK), and appear to damage the sound quality, first check if you have some IRQ problem, maybe sharing the soundcard IRQ with a broken or heavy loaded ethernet or graphic card. Then consider to increase the alsa_periods_in_buffer (now is set to %d) for this interface in the config file. delayp1=%d, delayp2=%d\n",
682            CELLIAX_P_LOG, p->alsa_periods_in_buffer, (int) delayp1, (int) delayp2);
683       }
684 
685     }
686 
687     memset(sizbuf2, 0, sizeof(sizbuf2));
688     if (p->alsa_play_is_mono) {
689       res = snd_pcm_writei(p->alsap, sizbuf, len / 2);
690     } else {
691       int a = 0;
692       int i = 0;
693       for (i = 0; i < 8000;) {
694         sizbuf2[a] = sizbuf[i];
695         a++;
696         i++;
697         sizbuf2[a] = sizbuf[i];
698         a++;
699         i--;
700         sizbuf2[a] = sizbuf[i]; // comment out this line to use only left
701         a++;
702         i++;
703         sizbuf2[a] = sizbuf[i]; // comment out this line to use only left
704         a++;
705         i++;
706       }
707       res = snd_pcm_writei(p->alsap, sizbuf2, len);
708     }
709     if (res == -EPIPE) {
710       DEBUGA_SOUND
711         ("ALSA write EPIPE (XRUN) (celliax can't fill the soundcard buffer fast enough). If this happens often (not after silence or after a pause in the speech, that's OK), and appear to damage the sound quality, first check if you have some IRQ problem, maybe sharing the soundcard IRQ with a broken or heavy loaded ethernet or graphic card. Then consider to increase the alsa_periods_in_buffer (now is set to %d) for this interface in the config file. delayp1=%d, delayp2=%d\n",
712          CELLIAX_P_LOG, p->alsa_periods_in_buffer, (int) delayp1, (int) delayp2);
713       res = snd_pcm_prepare(p->alsap);
714       if (res) {
715         ERRORA("audio play prepare failed: %s\n", CELLIAX_P_LOG, snd_strerror(res));
716       } else {
717 
718         if (p->alsa_play_is_mono) {
719           res = snd_pcm_writei(p->alsap, sizbuf, len / 2);
720         } else {
721           int a = 0;
722           int i = 0;
723           for (i = 0; i < 8000;) {
724             sizbuf2[a] = sizbuf[i];
725             a++;
726             i++;
727             sizbuf2[a] = sizbuf[i];
728             a++;
729             i--;
730             sizbuf2[a] = sizbuf[i];
731             a++;
732             i++;
733             sizbuf2[a] = sizbuf[i];
734             a++;
735             i++;
736           }
737           res = snd_pcm_writei(p->alsap, sizbuf2, len);
738         }
739 
740       }
741 
742     } else {
743       if (res == -ESTRPIPE) {
744         ERRORA("You've got some big problems\n", CELLIAX_P_LOG);
745       } else if (res == -EAGAIN) {
746         res = 0;
747       } else if (res < 0) {
748         ERRORA("Error %d on audio write: \"%s\"\n", CELLIAX_P_LOG, res,
749                snd_strerror(res));
750       }
751     }
752   }
753 
754   if (p->audio_play_reset_period) {
755     time(&now_timestamp);
756     if ((now_timestamp - p->audio_play_reset_timestamp) > p->audio_play_reset_period) {
757       if (option_debug)
758         DEBUGA_SOUND("reset audio play\n", CELLIAX_P_LOG);
759       res = snd_pcm_wait(p->alsap, 1000);
760       if (res < 0) {
761         ERRORA("audio play wait failed: %s\n", CELLIAX_P_LOG, snd_strerror(res));
762       }
763       res = snd_pcm_drop(p->alsap);
764       if (res) {
765         ERRORA("audio play drop failed: %s\n", CELLIAX_P_LOG, snd_strerror(res));
766       }
767       res = snd_pcm_prepare(p->alsap);
768       if (res) {
769         ERRORA("audio play prepare failed: %s\n", CELLIAX_P_LOG, snd_strerror(res));
770       }
771       res = snd_pcm_wait(p->alsap, 1000);
772       if (res < 0) {
773         ERRORA("audio play wait failed: %s\n", CELLIAX_P_LOG, snd_strerror(res));
774       }
775       time(&p->audio_play_reset_timestamp);
776     }
777   }
778   res = 0;
779   if (res > 0)
780     res = 0;
781   return res;
782 }
783 
784 
785 /*! \brief Write audio frames to interface */
786 #endif /* CELLIAX_ALSA */
787 
788 #ifdef CELLIAX_PORTAUDIO
celliax_portaudio_devlist(struct celliax_pvt * p)789 int celliax_portaudio_devlist(struct celliax_pvt *p)
790 {
791   int i, numDevices;
792   const PaDeviceInfo *deviceInfo;
793 
794   numDevices = Pa_GetDeviceCount();
795   if (numDevices < 0) {
796     return 0;
797   }
798   for (i = 0; i < numDevices; i++) {
799     deviceInfo = Pa_GetDeviceInfo(i);
800     NOTICA
801       ("Found PORTAUDIO device: id=%d\tname=%s\tmax input channels=%d\tmax output channels=%d\n",
802        CELLIAX_P_LOG, i, deviceInfo->name, deviceInfo->maxInputChannels,
803        deviceInfo->maxOutputChannels);
804   }
805 
806   return numDevices;
807 }
808 
celliax_portaudio_init(struct celliax_pvt * p)809 int celliax_portaudio_init(struct celliax_pvt *p)
810 {
811   PaError err;
812   int c;
813   PaStreamParameters inputParameters, outputParameters;
814   int numdevices;
815   const PaDeviceInfo *deviceInfo;
816 
817 #ifndef GIOVA48
818   setenv("PA_ALSA_PLUGHW", "1", 1);
819 #endif // GIOVA48
820 
821   err = Pa_Initialize();
822   if (err != paNoError)
823     return err;
824 
825   numdevices = celliax_portaudio_devlist(p);
826 
827   if (p->portaudiocindex > (numdevices - 1)) {
828     ERRORA("Portaudio Capture id=%d is out of range: valid id are from 0 to %d\n",
829            CELLIAX_P_LOG, p->portaudiocindex, (numdevices - 1));
830     return -1;
831   }
832 
833   if (p->portaudiopindex > (numdevices - 1)) {
834     ERRORA("Portaudio Playback id=%d is out of range: valid id are from 0 to %d\n",
835            CELLIAX_P_LOG, p->portaudiopindex, (numdevices - 1));
836     return -1;
837   }
838   //inputParameters.device = 0;
839   if (p->portaudiocindex != -1) {
840     inputParameters.device = p->portaudiocindex;
841   } else {
842     inputParameters.device = Pa_GetDefaultInputDevice();
843   }
844   deviceInfo = Pa_GetDeviceInfo(inputParameters.device);
845   NOTICA
846     ("Using INPUT PORTAUDIO device: id=%d\tname=%s\tmax input channels=%d\tmax output channels=%d\n",
847      CELLIAX_P_LOG, inputParameters.device, deviceInfo->name,
848      deviceInfo->maxInputChannels, deviceInfo->maxOutputChannels);
849   if (deviceInfo->maxInputChannels == 0) {
850     ERRORA
851       ("No INPUT channels on device: id=%d\tname=%s\tmax input channels=%d\tmax output channels=%d\n",
852        CELLIAX_P_LOG, inputParameters.device, deviceInfo->name,
853        deviceInfo->maxInputChannels, deviceInfo->maxOutputChannels);
854     return -1;
855   }
856   inputParameters.channelCount = 1;
857   inputParameters.sampleFormat = paInt16;
858   //inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultHighInputLatency;
859   inputParameters.suggestedLatency = 0.1;
860   inputParameters.hostApiSpecificStreamInfo = NULL;
861 
862   //outputParameters.device = 3;
863   if (p->portaudiopindex != -1) {
864     outputParameters.device = p->portaudiopindex;
865   } else {
866     outputParameters.device = Pa_GetDefaultOutputDevice();
867   }
868   deviceInfo = Pa_GetDeviceInfo(outputParameters.device);
869   NOTICA
870     ("Using OUTPUT PORTAUDIO device: id=%d\tname=%s\tmax input channels=%d\tmax output channels=%d\n",
871      CELLIAX_P_LOG, outputParameters.device, deviceInfo->name,
872      deviceInfo->maxInputChannels, deviceInfo->maxOutputChannels);
873   if (deviceInfo->maxOutputChannels == 0) {
874     ERRORA
875       ("No OUTPUT channels on device: id=%d\tname=%s\tmax input channels=%d\tmax output channels=%d\n",
876        CELLIAX_P_LOG, inputParameters.device, deviceInfo->name,
877        deviceInfo->maxInputChannels, deviceInfo->maxOutputChannels);
878     return -1;
879   }
880 #ifndef GIOVA48
881   outputParameters.channelCount = 1;
882 #else // GIOVA48
883   outputParameters.channelCount = 2;
884 #endif // GIOVA48
885   outputParameters.sampleFormat = paInt16;
886   //outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultHighOutputLatency;
887   outputParameters.suggestedLatency = 0.1;
888   outputParameters.hostApiSpecificStreamInfo = NULL;
889 
890 /* build the pipe that will be polled on by pbx */
891   c = pipe(p->audiopipe);
892   if (c) {
893     ERRORA("Unable to create audio pipe\n", CELLIAX_P_LOG);
894     return -1;
895   }
896   fcntl(p->audiopipe[0], F_SETFL, O_NONBLOCK);
897   fcntl(p->audiopipe[1], F_SETFL, O_NONBLOCK);
898 
899   err =
900 #ifndef GIOVA48
901     OpenAudioStream(&p->stream, &inputParameters, &outputParameters, 8000,
902                     paDitherOff | paClipOff, SAMPLES_PER_FRAME, p->audiopipe[1],
903                     &p->speexecho, &p->speexpreprocess, &p->owner);
904 
905 #else // GIOVA48
906     OpenAudioStream(&p->stream, &inputParameters, &outputParameters, 48000,
907                     paDitherOff | paClipOff, SAMPLES_PER_FRAME, p->audiopipe[1],
908                     &p->speexecho, &p->speexpreprocess, &p->owner);
909 
910 #endif // GIOVA48
911   if (err != paNoError) {
912     ERRORA("Unable to open audio stream: %s\n", CELLIAX_P_LOG, Pa_GetErrorText(err));
913     return -1;
914   }
915 
916 /* the pipe is our audio fd for pbx to poll on */
917   p->celliax_sound_capt_fd = p->audiopipe[0];
918 
919   return 0;
920 }
921 
celliax_portaudio_write(struct celliax_pvt * p,struct ast_frame * f)922 int celliax_portaudio_write(struct celliax_pvt *p, struct ast_frame *f)
923 {
924   int samples;
925 #ifdef GIOVA48
926   //short buf[CELLIAX_FRAME_SIZE * 2];
927   short buf[3840];
928   short *buf2;
929 
930   //ERRORA("1 f->datalen=: %d\n", CELLIAX_P_LOG, f->datalen);
931 
932   memset(buf, '\0', CELLIAX_FRAME_SIZE * 2);
933 
934   buf2 = f->data;
935 
936   int i = 0, a = 0;
937 
938   for (i = 0; i < f->datalen / sizeof(short); i++) {
939 //stereo, 2 chan 48 -> mono 8
940     buf[a] = buf2[i];
941     a++;
942     buf[a] = buf2[i];
943     a++;
944     buf[a] = buf2[i];
945     a++;
946     buf[a] = buf2[i];
947     a++;
948     buf[a] = buf2[i];
949     a++;
950     buf[a] = buf2[i];
951     a++;
952     buf[a] = buf2[i];
953     a++;
954     buf[a] = buf2[i];
955     a++;
956     buf[a] = buf2[i];
957     a++;
958     buf[a] = buf2[i];
959     a++;
960     buf[a] = buf2[i];
961     a++;
962     buf[a] = buf2[i];
963     a++;
964     /*
965      */
966   }
967   f->data = &buf;
968   f->datalen = f->datalen * 6;
969   //ERRORA("2 f->datalen=: %d\n", CELLIAX_P_LOG, f->datalen);
970   //f->datalen = f->datalen;
971 #endif // GIOVA48
972 
973 #ifdef ASTERISK_VERSION_1_6_0_1
974   samples =
975     WriteAudioStream(p->stream, (short *) f->data.ptr,
976                      (int) (f->datalen / sizeof(short)));
977 #else
978   samples =
979     WriteAudioStream(p->stream, (short *) f->data, (int) (f->datalen / sizeof(short)));
980 #endif /* ASTERISK_VERSION_1_6_0_1 */
981 
982   if (samples != (int) (f->datalen / sizeof(short)))
983     ERRORA("WriteAudioStream wrote: %d of %d\n", CELLIAX_P_LOG, samples,
984            (int) (f->datalen / sizeof(short)));
985 
986   return 0;
987 }
988 
celliax_portaudio_read(struct celliax_pvt * p)989 struct ast_frame *celliax_portaudio_read(struct celliax_pvt *p)
990 {
991   static struct ast_frame f;
992   static short __buf[CELLIAX_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2];
993   short *buf;
994   static short __buf2[CELLIAX_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2];
995   short *buf2;
996   int samples;
997   char c;
998 
999   memset(__buf, '\0', (CELLIAX_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2));
1000 
1001   buf = __buf + AST_FRIENDLY_OFFSET / 2;
1002 
1003   memset(__buf2, '\0', (CELLIAX_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2));
1004 
1005   buf2 = __buf2 + AST_FRIENDLY_OFFSET / 2;
1006 
1007   f.frametype = AST_FRAME_NULL;
1008   f.subclass = 0;
1009   f.samples = 0;
1010   f.datalen = 0;
1011 
1012 #ifdef ASTERISK_VERSION_1_6_0_1
1013   f.data.ptr = NULL;
1014 #else
1015   f.data = NULL;
1016 #endif /* ASTERISK_VERSION_1_6_0_1 */
1017   f.offset = 0;
1018   f.src = celliax_type;
1019   f.mallocd = 0;
1020   f.delivery.tv_sec = 0;
1021   f.delivery.tv_usec = 0;
1022 
1023   if ((samples = ReadAudioStream(p->stream, buf, SAMPLES_PER_FRAME)) == 0) {
1024     //do nothing
1025   } else {
1026 #ifdef GIOVA48
1027     int i = 0, a = 0;
1028 
1029     samples = samples / 6;
1030     for (i = 0; i < samples; i++) {
1031       buf2[i] = buf[a];
1032       a = a + 6;                //mono, 1 chan 48 -> 8
1033     }
1034     buf = buf2;
1035 
1036     /* A real frame */
1037     f.frametype = AST_FRAME_VOICE;
1038     f.subclass = AST_FORMAT_SLINEAR;
1039     f.samples = CELLIAX_FRAME_SIZE / 6;
1040     f.datalen = CELLIAX_FRAME_SIZE * 2 / 6;
1041 #else // GIOVA48
1042     /* A real frame */
1043     f.frametype = AST_FRAME_VOICE;
1044     f.subclass = AST_FORMAT_SLINEAR;
1045     f.samples = CELLIAX_FRAME_SIZE;
1046     f.datalen = CELLIAX_FRAME_SIZE * 2;
1047 #endif // GIOVA48
1048 
1049 #ifdef ASTERISK_VERSION_1_6_0_1
1050     f.data.ptr = buf;
1051 #else
1052     f.data = buf;
1053 #endif /* ASTERISK_VERSION_1_6_0_1 */
1054     f.offset = AST_FRIENDLY_OFFSET;
1055     f.src = celliax_type;
1056     f.mallocd = 0;
1057   }
1058 
1059   read(p->audiopipe[0], &c, 1);
1060 
1061   return &f;
1062 }
1063 
celliax_portaudio_shutdown(struct celliax_pvt * p)1064 int celliax_portaudio_shutdown(struct celliax_pvt *p)
1065 {
1066   PaError err;
1067 
1068   err = CloseAudioStream(p->stream);
1069 
1070   if (err != paNoError)
1071     ERRORA("not able to CloseAudioStream\n", CELLIAX_P_LOG);
1072 
1073   Pa_Terminate();
1074   return 0;
1075 }
1076 #endif // CELLIAX_PORTAUDIO
1077 
celliax_serial_sync_AT(struct celliax_pvt * p)1078 int celliax_serial_sync_AT(struct celliax_pvt *p)
1079 {
1080   usleep(10000);                /* 10msec */
1081   time(&p->celliax_serial_synced_timestamp);
1082   return 0;
1083 }
1084 
celliax_serial_getstatus_AT(struct celliax_pvt * p)1085 int celliax_serial_getstatus_AT(struct celliax_pvt *p)
1086 {
1087   int res;
1088 
1089   if (p->owner) {
1090     if (p->owner->_state != AST_STATE_UP && p->owner->_state != AST_STATE_DOWN) {
1091       DEBUGA_AT("No getstatus, we're neither UP nor DOWN\n", CELLIAX_P_LOG);
1092       return 0;
1093     }
1094   }
1095 
1096   PUSHA_UNLOCKA(&p->controldev_lock);
1097   LOKKA(&p->controldev_lock);
1098   res = celliax_serial_write_AT_ack(p, "AT");
1099   if (res) {
1100     ERRORA("AT was not acknowledged, continuing but maybe there is a problem\n",
1101            CELLIAX_P_LOG);
1102   }
1103   usleep(1000);
1104 
1105   if (strlen(p->at_query_battchg)) {
1106     res =
1107       celliax_serial_write_AT_expect(p, p->at_query_battchg, p->at_query_battchg_expect);
1108     if (res) {
1109       WARNINGA("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
1110                p->at_query_battchg, p->at_query_battchg_expect);
1111     }
1112     usleep(1000);
1113   }
1114 
1115   if (strlen(p->at_query_signal)) {
1116     res =
1117       celliax_serial_write_AT_expect(p, p->at_query_signal, p->at_query_signal_expect);
1118     if (res) {
1119       WARNINGA("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
1120                p->at_query_signal, p->at_query_signal_expect);
1121     }
1122     usleep(1000);
1123   }
1124   //FIXME all the following commands in config!
1125 
1126   if (p->sms_cnmi_not_supported) {
1127     res = celliax_serial_write_AT_ack(p, "AT+MMGL=\"HEADER ONLY\"");
1128     if (res) {
1129       WARNINGA
1130         ("%s does not get %s from the modem, maybe a long msg is incoming. If this cellmodem is not a Motorola, you are arriving here because your cellmodem do not supports CNMI kind of incoming SMS alert; please let it know to the developers of Celliax. If this cellmodem is a Motorola and this message keeps repeating, and you cannot correctly receive SMSs from this interface, please manually clean all messages from the cellmodem/SIM. Continuing.\n",
1131          CELLIAX_P_LOG, "AT+MMGL=\"HEADER ONLY\"", "OK");
1132     } else {
1133       usleep(1000);
1134       if (p->unread_sms_msg_id) {
1135         char at_command[256];
1136 
1137         if (p->no_ucs2 == 0) {
1138           res = celliax_serial_write_AT_ack(p, "AT+CSCS=\"UCS2\"");
1139           if (res) {
1140             ERRORA
1141               ("AT+CSCS=\"UCS2\" (set TE messages to ucs2)  do not got OK from the phone\n",
1142                CELLIAX_P_LOG);
1143             memset(p->sms_message, 0, sizeof(p->sms_message));
1144           }
1145         }
1146 
1147         memset(at_command, 0, sizeof(at_command));
1148         sprintf(at_command, "AT+CMGR=%d", p->unread_sms_msg_id);
1149         memset(p->sms_message, 0, sizeof(p->sms_message));
1150 
1151         p->reading_sms_msg = 1;
1152         res = celliax_serial_write_AT_ack(p, at_command);
1153         p->reading_sms_msg = 0;
1154         if (res) {
1155           ERRORA
1156             ("AT+CMGR (read SMS) do not got OK from the phone, message sent was:|||%s|||\n",
1157              CELLIAX_P_LOG, at_command);
1158         }
1159         res = celliax_serial_write_AT_ack(p, "AT+CSCS=\"GSM\"");
1160         if (res) {
1161           ERRORA
1162             ("AT+CSCS=\"GSM\" (set TE messages to GSM) do not got OK from the phone\n",
1163              CELLIAX_P_LOG);
1164         }
1165         memset(at_command, 0, sizeof(at_command));
1166         sprintf(at_command, "AT+CMGD=%d", p->unread_sms_msg_id);    /* delete the message */
1167         p->unread_sms_msg_id = 0;
1168         res = celliax_serial_write_AT_ack(p, at_command);
1169         if (res) {
1170           ERRORA
1171             ("AT+CMGD (Delete SMS) do not got OK from the phone, message sent was:|||%s|||\n",
1172              CELLIAX_P_LOG, at_command);
1173         }
1174 
1175         if (strlen(p->sms_message)) {
1176 
1177           manager_event(EVENT_FLAG_SYSTEM, "CELLIAXincomingsms",
1178                         "Interface: %s\r\nSMS_Message: %s\r\n", p->name, p->sms_message);
1179 
1180           if (strlen(p->sms_receiving_program)) {
1181             int fd1[2];
1182             pid_t pid1;
1183             char *arg1[] = { p->sms_receiving_program, (char *) NULL };
1184             int i;
1185 
1186             NOTICA("incoming SMS message:>>>%s<<<\n", CELLIAX_P_LOG, p->sms_message);
1187             pipe(fd1);
1188             pid1 = switch_fork();
1189 
1190             if (pid1 == 0) {    //child
1191               int err;
1192 
1193               dup2(fd1[0], 0);  // Connect stdin to pipe output
1194               close(fd1[1]);    // close input pipe side
1195               setsid();         //session id
1196               err = execvp(arg1[0], arg1);  //exec our program, with stdin connected to pipe output
1197               if (err) {
1198                 ERRORA
1199                   ("'sms_receiving_program' is set in config file to '%s', and it gave us back this error: %d, (%s). SMS received was:---%s---\n",
1200                    CELLIAX_P_LOG, p->sms_receiving_program, err, strerror(errno),
1201                    p->sms_message);
1202               }
1203               close(fd1[0]);    // close output pipe side
1204             }                   //starting here continue the parent
1205             close(fd1[0]);      // close output pipe side
1206             // write the msg on the pipe input
1207             for (i = 0; i < strlen(p->sms_message); i++) {
1208               write(fd1[1], &p->sms_message[i], 1);
1209             }
1210             close(fd1[1]);      // close pipe input, let our program know we've finished
1211           } else {
1212             ERRORA
1213               ("got SMS incoming message, but 'sms_receiving_program' is not set in config file. SMS received was:---%s---\n",
1214                CELLIAX_P_LOG, p->sms_message);
1215           }
1216         }
1217 #if 1                           //is this one needed? maybe it can interrupt an incoming call that is just to announce itself
1218         if (p->phone_callflow == CALLFLOW_CALL_IDLE
1219             && p->interface_state == AST_STATE_DOWN && p->owner == NULL) {
1220           /* we're not in a call, neither calling */
1221           res = celliax_serial_write_AT_ack(p, "AT+CKPD=\"EEE\"");
1222           if (res) {
1223             ERRORA
1224               ("AT+CKPD=\"EEE\" (cellphone screen back to user) do not got OK from the phone\n",
1225                CELLIAX_P_LOG);
1226           }
1227         }
1228 #endif
1229       }
1230     }
1231   }
1232 
1233   UNLOCKA(&p->controldev_lock);
1234   POPPA_UNLOCKA(&p->controldev_lock);
1235   return 0;
1236 }
1237 
celliax_serial_read_AT(struct celliax_pvt * p,int look_for_ack,int timeout_usec,int timeout_sec,const char * expected_string,int expect_crlf)1238 int celliax_serial_read_AT(struct celliax_pvt *p, int look_for_ack, int timeout_usec,
1239                            int timeout_sec, const char *expected_string, int expect_crlf)
1240 {
1241   int select_err;
1242   int res;
1243   fd_set read_fds;
1244   struct timeval timeout;
1245   char tmp_answer[AT_BUFSIZ];
1246   char tmp_answer2[AT_BUFSIZ];
1247   char *tmp_answer_ptr;
1248   char *last_line_ptr;
1249   int i = 0;
1250   int read_count = 0;
1251   int la_counter = 0;
1252   int at_ack = -1;
1253   int la_read = 0;
1254 
1255   FD_ZERO(&read_fds);
1256   FD_SET(p->controldevfd, &read_fds);
1257 
1258   //NOTICA (" INSIDE this celliax_serial_device %s \n", CELLIAX_P_LOG, p->controldevice_name);
1259   tmp_answer_ptr = tmp_answer;
1260   memset(tmp_answer, 0, sizeof(char) * AT_BUFSIZ);
1261 
1262   timeout.tv_sec = timeout_sec;
1263   timeout.tv_usec = timeout_usec;
1264   PUSHA_UNLOCKA(&p->controldev_lock);
1265   LOKKA(&p->controldev_lock);
1266 
1267   while ((select_err = select(p->controldevfd + 1, &read_fds, NULL, NULL, &timeout)) > 0) {
1268     timeout.tv_sec = timeout_sec;   //reset the timeout, linux modify it
1269     timeout.tv_usec = timeout_usec; //reset the timeout, linux modify it
1270     read_count =
1271       read(p->controldevfd, tmp_answer_ptr, AT_BUFSIZ - (tmp_answer_ptr - tmp_answer));
1272 
1273     if (read_count == 0) {
1274       ERRORA
1275         ("read 0 bytes!!! Nenormalno! Marking this celliax_serial_device %s as dead, andif it is owned by a channel, hanging up. Maybe the phone is stuck, switched off, power down or battery exhausted\n",
1276          CELLIAX_P_LOG, p->controldevice_name);
1277       p->controldev_dead = 1;
1278       close(p->controldevfd);
1279       UNLOCKA(&p->controldev_lock);
1280       if (p->owner) {
1281         p->owner->hangupcause = AST_CAUSE_FAILURE;
1282         celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
1283       }
1284       return -1;
1285     }
1286 
1287     if (option_debug > 90) {
1288       //DEBUGA_AT("1 read %d bytes, --|%s|--\n", CELLIAX_P_LOG, read_count, tmp_answer_ptr);
1289       //DEBUGA_AT("2 read %d bytes, --|%s|--\n", CELLIAX_P_LOG, read_count, tmp_answer);
1290     }
1291     tmp_answer_ptr = tmp_answer_ptr + read_count;
1292 
1293     char *token_ptr;
1294 
1295     la_counter = 0;
1296     memset(tmp_answer2, 0, sizeof(char) * AT_BUFSIZ);
1297     strcpy(tmp_answer2, tmp_answer);
1298     if ((token_ptr = strtok(tmp_answer2, "\n\r"))) {
1299       last_line_ptr = token_ptr;
1300       strncpy(p->line_array.result[la_counter], token_ptr, AT_MESG_MAX_LENGTH);
1301       if (strlen(token_ptr) > AT_MESG_MAX_LENGTH) {
1302         WARNINGA
1303           ("AT mesg longer than buffer, original message was: |%s|, in buffer only: |%s|\n",
1304            CELLIAX_P_LOG, token_ptr, p->line_array.result[la_counter]);
1305       }
1306       la_counter++;
1307       while ((token_ptr = strtok(NULL, "\n\r"))) {
1308         last_line_ptr = token_ptr;
1309         strncpy(p->line_array.result[la_counter], token_ptr, AT_MESG_MAX_LENGTH);
1310         if (strlen(token_ptr) > AT_MESG_MAX_LENGTH) {
1311           WARNINGA
1312             ("AT mesg longer than buffer, original message was: |%s|, in buffer only: |%s|\n",
1313              CELLIAX_P_LOG, token_ptr, p->line_array.result[la_counter]);
1314         }
1315         la_counter++;
1316       }
1317     } else {
1318       last_line_ptr = tmp_answer;
1319     }
1320 
1321     if (expected_string && !expect_crlf) {
1322       DEBUGA_AT
1323         ("last_line_ptr=|%s|, expected_string=|%s|, expect_crlf=%d, memcmp(last_line_ptr, expected_string, strlen(expected_string)) = %d\n",
1324          CELLIAX_P_LOG, last_line_ptr, expected_string, expect_crlf, memcmp(last_line_ptr,
1325                                                                             expected_string,
1326                                                                             strlen
1327                                                                             (expected_string)));
1328     }
1329 
1330     if (expected_string && !expect_crlf
1331         && !memcmp(last_line_ptr, expected_string, strlen(expected_string))
1332       ) {
1333       strncpy(p->line_array.result[la_counter], last_line_ptr, AT_MESG_MAX_LENGTH);
1334       // match expected string -> accept it withtout CRLF
1335       la_counter++;
1336 
1337     }
1338     /* if the last line read was not a complete line, we'll read the rest in the future */
1339     else if (tmp_answer[strlen(tmp_answer) - 1] != '\r'
1340              && tmp_answer[strlen(tmp_answer) - 1] != '\n')
1341       la_counter--;
1342 
1343     /* let's list the complete lines read so far, without re-listing the lines that has yet been listed */
1344     if (option_debug > 1) {
1345       for (i = la_read; i < la_counter; i++)
1346         DEBUGA_AT("Read line %d: |%s|\n", CELLIAX_P_LOG, i, p->line_array.result[i]);
1347     }
1348 
1349     /* let's interpret the complete lines read so far (WITHOUT looking for OK, ERROR, and EXPECTED_STRING), without re-interpreting the lines that has been yet interpreted, so we're sure we don't miss anything */
1350     for (i = la_read; i < la_counter; i++) {
1351 
1352       if ((strcmp(p->line_array.result[i], "RING") == 0)) {
1353         /* with first RING we wait for callid */
1354         gettimeofday(&(p->ringtime), NULL);
1355         /* give CALLID (+CLIP) a chance, wait for the next RING before answering */
1356         if (p->phone_callflow == CALLFLOW_INCOMING_RING) {
1357           /* we're at the second ring, set the interface state, will be answered by celliax_do_monitor */
1358           DEBUGA_AT("|%s| got second RING\n", CELLIAX_P_LOG, p->line_array.result[i]);
1359           p->interface_state = AST_STATE_RING;
1360         } else {
1361           /* we're at the first ring, so there is no CALLID yet thus clean the previous one
1362              just in case we don't receive the caller identification in this new call */
1363           memset(p->callid_name, 0, sizeof(p->callid_name));
1364           memset(p->callid_number, 0, sizeof(p->callid_number));
1365           /* only send AT+CLCC? if the device previously reported its support */
1366           if (p->at_has_clcc != 0) {
1367             /* we're at the first ring, try to get CALLID (with +CLCC) */
1368             DEBUGA_AT("|%s| got first RING, sending AT+CLCC?\n", CELLIAX_P_LOG,
1369                       p->line_array.result[i]);
1370             res = celliax_serial_write_AT_noack(p, "AT+CLCC?");
1371             if (res) {
1372               ERRORA("AT+CLCC? (call list) was not correctly sent to the phone\n",
1373                      CELLIAX_P_LOG);
1374             }
1375           } else {
1376             DEBUGA_AT("|%s| got first RING, but not sending AT+CLCC? as this device "
1377                       "seems not to support\n", CELLIAX_P_LOG, p->line_array.result[i]);
1378           }
1379         }
1380         p->phone_callflow = CALLFLOW_INCOMING_RING;
1381       }
1382 
1383       if ((strncmp(p->line_array.result[i], "+CLCC", 5) == 0)) {
1384         /* with clcc we wait for clip */
1385         memset(p->callid_name, 0, sizeof(p->callid_name));
1386         memset(p->callid_number, 0, sizeof(p->callid_number));
1387         int commacount = 0;
1388         int a = 0;
1389         int b = 0;
1390         int c = 0;
1391 
1392         for (a = 0; a < strlen(p->line_array.result[i]); a++) {
1393 
1394           if (p->line_array.result[i][a] == ',') {
1395             commacount++;
1396           }
1397           if (commacount == 5) {
1398             if (p->line_array.result[i][a] != ',' && p->line_array.result[i][a] != '"') {
1399               p->callid_number[b] = p->line_array.result[i][a];
1400               b++;
1401             }
1402           }
1403           if (commacount == 7) {
1404             if (p->line_array.result[i][a] != ',' && p->line_array.result[i][a] != '"') {
1405               p->callid_name[c] = p->line_array.result[i][a];
1406               c++;
1407             }
1408           }
1409         }
1410 
1411         p->phone_callflow = CALLFLOW_INCOMING_RING;
1412         DEBUGA_AT("|%s| CLCC CALLID: name is %s, number is %s\n", CELLIAX_P_LOG,
1413                   p->line_array.result[i],
1414                   p->callid_name[0] ? p->callid_name : "not available",
1415                   p->callid_number[0] ? p->callid_number : "not available");
1416       }
1417 
1418       if ((strncmp(p->line_array.result[i], "+CLIP", 5) == 0)) {
1419         /* with CLIP, we want to answer right away */
1420         memset(p->callid_name, 0, sizeof(p->callid_name));
1421         memset(p->callid_number, 0, sizeof(p->callid_number));
1422 
1423         int commacount = 0;
1424         int a = 0;
1425         int b = 0;
1426         int c = 0;
1427 
1428         for (a = 7; a < strlen(p->line_array.result[i]); a++) {
1429           if (p->line_array.result[i][a] == ',') {
1430             commacount++;
1431           }
1432           if (commacount == 0) {
1433             if (p->line_array.result[i][a] != ',' && p->line_array.result[i][a] != '"') {
1434               p->callid_number[b] = p->line_array.result[i][a];
1435               b++;
1436             }
1437           }
1438           if (commacount == 4) {
1439             if (p->line_array.result[i][a] != ',' && p->line_array.result[i][a] != '"') {
1440               p->callid_name[c] = p->line_array.result[i][a];
1441               c++;
1442             }
1443           }
1444         }
1445 
1446         if (p->interface_state != AST_STATE_RING) {
1447           gettimeofday(&(p->call_incoming_time), NULL);
1448           DEBUGA_AT("AST_STATE_RING call_incoming_time.tv_sec=%ld\n",
1449                     CELLIAX_P_LOG, p->call_incoming_time.tv_sec);
1450 
1451         }
1452 
1453         p->interface_state = AST_STATE_RING;
1454         p->phone_callflow = CALLFLOW_INCOMING_RING;
1455         DEBUGA_AT("|%s| CLIP INCOMING CALLID: name is %s, number is %s\n", CELLIAX_P_LOG,
1456                   p->line_array.result[i],
1457                   p->callid_name[0] != 1 ? p->callid_name : "not available",
1458                   p->callid_number[0] ? p->callid_number : "not available");
1459       }
1460 
1461       if ((strcmp(p->line_array.result[i], "BUSY") == 0)) {
1462         p->phone_callflow = CALLFLOW_CALL_LINEBUSY;
1463         if (option_debug > 1)
1464           DEBUGA_AT("|%s| CALLFLOW_CALL_LINEBUSY\n", CELLIAX_P_LOG,
1465                     p->line_array.result[i]);
1466         if (p->interface_state != AST_STATE_DOWN && p->owner) {
1467           ast_setstate(p->owner, AST_STATE_BUSY);
1468           celliax_queue_control(p->owner, AST_CONTROL_BUSY);
1469         } else {
1470           ERRORA("Why BUSY now?\n", CELLIAX_P_LOG);
1471         }
1472       }
1473       if ((strcmp(p->line_array.result[i], "NO ANSWER") == 0)) {
1474         p->phone_callflow = CALLFLOW_CALL_NOANSWER;
1475         if (option_debug > 1)
1476           DEBUGA_AT("|%s| CALLFLOW_CALL_NOANSWER\n", CELLIAX_P_LOG,
1477                     p->line_array.result[i]);
1478         if (p->interface_state != AST_STATE_DOWN && p->owner) {
1479           p->owner->hangupcause = AST_CAUSE_NO_ANSWER;
1480           celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
1481         } else {
1482           ERRORA("Why NO ANSWER now?\n", CELLIAX_P_LOG);
1483         }
1484       }
1485       if ((strcmp(p->line_array.result[i], "NO CARRIER") == 0)) {
1486 	      if (p->phone_callflow != CALLFLOW_CALL_HANGUP_REQUESTED) {
1487 		      p->phone_callflow = CALLFLOW_CALL_NOCARRIER;
1488 		      if (option_debug > 1)
1489 			      DEBUGA_AT("|%s| CALLFLOW_CALL_NOCARRIER\n", CELLIAX_P_LOG,
1490 					      p->line_array.result[i]);
1491 		      p->control_to_send = 0;
1492 		      usleep(20000);
1493 		      if (p->interface_state != AST_STATE_DOWN && p->owner) {
1494 			      p->owner->hangupcause = AST_CAUSE_FAILURE;
1495 			      celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
1496 		      } else {
1497 			      ERRORA("Why NO CARRIER now?\n", CELLIAX_P_LOG);
1498 		      }
1499 	      }
1500       }
1501 
1502       if ((strncmp(p->line_array.result[i], "+CBC:", 5) == 0)) {
1503         int power_supply, battery_strenght, err;
1504 
1505         power_supply = battery_strenght = 0;
1506 
1507         err =
1508           sscanf(&p->line_array.result[i][6], "%d,%d", &power_supply, &battery_strenght);
1509         if (err < 2) {
1510           DEBUGA_AT("|%s| is not formatted as: |+CBC: xx,yy| now trying  |+CBC:xx,yy|\n",
1511                     CELLIAX_P_LOG, p->line_array.result[i]);
1512 
1513           err =
1514             sscanf(&p->line_array.result[i][5], "%d,%d", &power_supply,
1515                    &battery_strenght);
1516           DEBUGA_AT("|%s| +CBC: Powered by %s, battery strenght=%d\n", CELLIAX_P_LOG,
1517                     p->line_array.result[i], power_supply ? "power supply" : "battery",
1518                     battery_strenght);
1519 
1520         }
1521 
1522         if (err < 2) {
1523           DEBUGA_AT("|%s| is not formatted as: |+CBC:xx,yy| giving up\n", CELLIAX_P_LOG,
1524                     p->line_array.result[i]);
1525         }
1526 
1527         else {
1528           if (option_debug > 1)
1529             DEBUGA_AT("|%s| +CBC: Powered by %s, battery strenght=%d\n", CELLIAX_P_LOG,
1530                       p->line_array.result[i], power_supply ? "power supply" : "battery",
1531                       battery_strenght);
1532           if (!power_supply) {
1533             if (battery_strenght < 10) {
1534               ERRORA("|%s| BATTERY ALMOST EXHAUSTED\n", CELLIAX_P_LOG,
1535                      p->line_array.result[i]);
1536             } else if (battery_strenght < 20) {
1537               WARNINGA("|%s| BATTERY LOW\n", CELLIAX_P_LOG, p->line_array.result[i]);
1538 
1539             }
1540 
1541           }
1542         }
1543 
1544       }
1545 
1546       if ((strncmp(p->line_array.result[i], "+CSQ:", 5) == 0)) {
1547         int signal_quality, ber, err;
1548 
1549         signal_quality = ber = 0;
1550 
1551         err = sscanf(&p->line_array.result[i][6], "%d,%d", &signal_quality, &ber);
1552         if (option_debug > 1)
1553           DEBUGA_AT("|%s| +CSQ: Signal Quality: %d, Error Rate=%d\n", CELLIAX_P_LOG,
1554                     p->line_array.result[i], signal_quality, ber);
1555         if (err < 2) {
1556           ERRORA("|%s| is not formatted as: |+CSQ: xx,yy|\n", CELLIAX_P_LOG,
1557                  p->line_array.result[i]);
1558         } else {
1559           if (signal_quality < 11 || signal_quality == 99) {
1560             WARNINGA
1561               ("|%s| CELLPHONE GETS ALMOST NO SIGNAL, consider to move it or additional antenna\n",
1562                CELLIAX_P_LOG, p->line_array.result[i]);
1563           } else if (signal_quality < 15) {
1564             WARNINGA("|%s| CELLPHONE GETS SIGNAL LOW\n", CELLIAX_P_LOG,
1565                      p->line_array.result[i]);
1566 
1567           }
1568 
1569         }
1570 
1571       }
1572       if ((strncmp(p->line_array.result[i], "+CMGW:", 6) == 0)) {
1573         int err;
1574 
1575         err = sscanf(&p->line_array.result[i][7], "%s", p->at_cmgw);
1576         DEBUGA_AT("|%s| +CMGW: %s\n", CELLIAX_P_LOG, p->line_array.result[i], p->at_cmgw);
1577         if (err < 1) {
1578           ERRORA("|%s| is not formatted as: |+CMGW: xxxx|\n", CELLIAX_P_LOG,
1579                  p->line_array.result[i]);
1580         }
1581 
1582       }
1583 
1584       /* at_call_* are unsolicited messages sent by the modem to signal us about call processing activity and events */
1585       if ((strcmp(p->line_array.result[i], p->at_call_idle) == 0)) {
1586         p->phone_callflow = CALLFLOW_CALL_IDLE;
1587         if (option_debug > 1)
1588           DEBUGA_AT("|%s| CALLFLOW_CALL_IDLE\n", CELLIAX_P_LOG, p->line_array.result[i]);
1589         if (p->interface_state != AST_STATE_DOWN && p->owner) {
1590           DEBUGA_AT("just received a remote HANGUP\n", CELLIAX_P_LOG);
1591           p->owner->hangupcause = AST_CAUSE_NORMAL;
1592           celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
1593           DEBUGA_AT("just sent AST_CONTROL_HANGUP\n", CELLIAX_P_LOG);
1594         }
1595       }
1596 
1597       if ((strcmp(p->line_array.result[i], p->at_call_incoming) == 0)) {
1598 
1599         //char list_command[64];
1600 
1601         if (option_debug > 1)
1602           DEBUGA_AT("|%s| CALLFLOW_CALL_INCOMING\n", CELLIAX_P_LOG,
1603                     p->line_array.result[i]);
1604 
1605         if (p->phone_callflow != CALLFLOW_CALL_INCOMING
1606             && p->phone_callflow != CALLFLOW_INCOMING_RING) {
1607           //mark the time of CALLFLOW_CALL_INCOMING
1608           gettimeofday(&(p->call_incoming_time), NULL);
1609           p->phone_callflow = CALLFLOW_CALL_INCOMING;
1610           DEBUGA_AT("CALLFLOW_CALL_INCOMING call_incoming_time.tv_sec=%ld\n",
1611                     CELLIAX_P_LOG, p->call_incoming_time.tv_sec);
1612 
1613         }
1614       }
1615 
1616       if ((strcmp(p->line_array.result[i], p->at_call_active) == 0)) {
1617         p->phone_callflow = CALLFLOW_CALL_ACTIVE;
1618         if (option_debug > 1)
1619           DEBUGA_AT("|%s| CALLFLOW_CALL_ACTIVE\n", CELLIAX_P_LOG,
1620                     p->line_array.result[i]);
1621 
1622         if (p->owner && p->interface_state == CALLFLOW_CALL_DIALING) {
1623           DEBUGA_PBX("just received a remote ANSWER\n", CELLIAX_P_LOG);
1624           if (p->owner->_state != AST_STATE_UP) {
1625             celliax_queue_control(p->owner, AST_CONTROL_RINGING);
1626             DEBUGA_PBX("just sent AST_CONTROL_RINGING\n", CELLIAX_P_LOG);
1627             DEBUGA_PBX("going to send AST_CONTROL_ANSWER\n", CELLIAX_P_LOG);
1628             celliax_queue_control(p->owner, AST_CONTROL_ANSWER);
1629             DEBUGA_PBX("just sent AST_CONTROL_ANSWER\n", CELLIAX_P_LOG);
1630           }
1631         } else {
1632         }
1633         p->interface_state = AST_STATE_UP;
1634         DEBUGA_PBX("just interface_state UP\n", CELLIAX_P_LOG);
1635       }
1636 
1637       if ((strcmp(p->line_array.result[i], p->at_call_calling) == 0)) {
1638         p->phone_callflow = CALLFLOW_CALL_DIALING;
1639         if (option_debug > 1)
1640           DEBUGA_AT("|%s| CALLFLOW_CALL_DIALING\n", CELLIAX_P_LOG,
1641                     p->line_array.result[i]);
1642       }
1643       if ((strcmp(p->line_array.result[i], p->at_call_failed) == 0)) {
1644         p->phone_callflow = CALLFLOW_CALL_FAILED;
1645         if (option_debug > 1)
1646           DEBUGA_AT("|%s| CALLFLOW_CALL_FAILED\n", CELLIAX_P_LOG,
1647                     p->line_array.result[i]);
1648         if (p->interface_state != AST_STATE_DOWN && p->owner) {
1649           p->owner->hangupcause = AST_CAUSE_FAILURE;
1650           celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
1651         }
1652       }
1653 
1654       if ((strncmp(p->line_array.result[i], "+CSCA:", 6) == 0)) {   //TODO SMS FIXME in config!
1655         if (option_debug > 1)
1656           DEBUGA_AT("|%s| +CSCA: Message Center Address!\n", CELLIAX_P_LOG,
1657                     p->line_array.result[i]);
1658       }
1659 
1660       if ((strncmp(p->line_array.result[i], "+CMGF:", 6) == 0)) {   //TODO SMS FIXME in config!
1661         if (option_debug > 1)
1662           DEBUGA_AT("|%s| +CMGF: Message Format!\n", CELLIAX_P_LOG,
1663                     p->line_array.result[i]);
1664       }
1665 
1666       if ((strncmp(p->line_array.result[i], "+CMTI:", 6) == 0)) {   //TODO SMS FIXME in config!
1667         int err;
1668         int pos;
1669 
1670         //FIXME all the following commands in config!
1671         if (option_debug)
1672           DEBUGA_AT("|%s| +CMTI: Incoming SMS!\n", CELLIAX_P_LOG,
1673                     p->line_array.result[i]);
1674 
1675         err = sscanf(&p->line_array.result[i][12], "%d", &pos);
1676         if (err < 1) {
1677           ERRORA("|%s| is not formatted as: |+CMTI: \"MT\",xx|\n", CELLIAX_P_LOG,
1678                  p->line_array.result[i]);
1679         } else {
1680           DEBUGA_AT("|%s| +CMTI: Incoming SMS in position: %d!\n", CELLIAX_P_LOG,
1681                     p->line_array.result[i], pos);
1682           p->unread_sms_msg_id = pos;
1683           usleep(1000);
1684 
1685           if (p->unread_sms_msg_id) {
1686             char at_command[256];
1687 
1688             if (p->no_ucs2 == 0) {
1689               res = celliax_serial_write_AT_ack(p, "AT+CSCS=\"UCS2\"");
1690               if (res) {
1691                 ERRORA
1692                   ("AT+CSCS=\"UCS2\" (set TE messages to ucs2)  do not got OK from the phone, continuing\n",
1693                    CELLIAX_P_LOG);
1694                 //memset(p->sms_message, 0, sizeof(p->sms_message));
1695               }
1696             }
1697 
1698             memset(at_command, 0, sizeof(at_command));
1699             sprintf(at_command, "AT+CMGR=%d", p->unread_sms_msg_id);
1700             memset(p->sms_message, 0, sizeof(p->sms_message));
1701 
1702             p->reading_sms_msg = 1;
1703             res = celliax_serial_write_AT_ack(p, at_command);
1704             p->reading_sms_msg = 0;
1705             if (res) {
1706               ERRORA
1707                 ("AT+CMGR (read SMS) do not got OK from the phone, message sent was:|||%s|||\n",
1708                  CELLIAX_P_LOG, at_command);
1709             }
1710             res = celliax_serial_write_AT_ack(p, "AT+CSCS=\"GSM\"");
1711             if (res) {
1712               ERRORA
1713                 ("AT+CSCS=\"GSM\" (set TE messages to GSM) do not got OK from the phone\n",
1714                  CELLIAX_P_LOG);
1715             }
1716             memset(at_command, 0, sizeof(at_command));
1717             sprintf(at_command, "AT+CMGD=%d", p->unread_sms_msg_id);    /* delete the message */
1718             p->unread_sms_msg_id = 0;
1719             res = celliax_serial_write_AT_ack(p, at_command);
1720             if (res) {
1721               ERRORA
1722                 ("AT+CMGD (Delete SMS) do not got OK from the phone, message sent was:|||%s|||\n",
1723                  CELLIAX_P_LOG, at_command);
1724             }
1725 
1726             if (strlen(p->sms_message)) {
1727               manager_event(EVENT_FLAG_SYSTEM, "CELLIAXincomingsms",
1728                             "Interface: %s\r\nSMS_Message: %s\r\n", p->name,
1729                             p->sms_message);
1730               if (strlen(p->sms_receiving_program)) {
1731                 int fd1[2];
1732                 pid_t pid1;
1733                 char *arg1[] = { p->sms_receiving_program, (char *) NULL };
1734                 int i;
1735 
1736                 NOTICA("incoming SMS message:>>>%s<<<\n", CELLIAX_P_LOG, p->sms_message);
1737                 pipe(fd1);
1738                 pid1 = switch_fork();
1739 
1740                 if (pid1 == 0) {    //child
1741                   int err;
1742 
1743                   dup2(fd1[0], 0);  // Connect stdin to pipe output
1744                   close(fd1[1]);    // close input pipe side
1745 		close(p->controldevfd);
1746                   setsid();     //session id
1747                   err = execvp(arg1[0], arg1);  //exec our program, with stdin connected to pipe output
1748                   if (err) {
1749                     ERRORA
1750                       ("'sms_receiving_program' is set in config file to '%s', and it gave us back this error: %d, (%s). SMS received was:---%s---\n",
1751                        CELLIAX_P_LOG, p->sms_receiving_program, err, strerror(errno),
1752                        p->sms_message);
1753                   }
1754                   close(fd1[0]);    // close output pipe side
1755                 }
1756 //starting here continue the parent
1757                 close(fd1[0]);  // close output pipe side
1758                 // write the msg on the pipe input
1759                 for (i = 0; i < strlen(p->sms_message); i++) {
1760                   write(fd1[1], &p->sms_message[i], 1);
1761                 }
1762                 close(fd1[1]);  // close pipe input, let our program know we've finished
1763               } else {
1764                 ERRORA
1765                   ("got SMS incoming message, but 'sms_receiving_program' is not set in config file. SMS received was:---%s---\n",
1766                    CELLIAX_P_LOG, p->sms_message);
1767               }
1768             }
1769 #if 1                           //is this one needed? maybe it can interrupt an incoming call that is just to announce itself
1770             if (p->phone_callflow == CALLFLOW_CALL_IDLE
1771                 && p->interface_state == AST_STATE_DOWN && p->owner == NULL) {
1772               /* we're not in a call, neither calling */
1773               res = celliax_serial_write_AT_ack(p, "AT+CKPD=\"EEE\"");
1774               if (res) {
1775                 ERRORA
1776                   ("AT+CKPD=\"EEE\" (cellphone screen back to user) do not got OK from the phone\n",
1777                    CELLIAX_P_LOG);
1778               }
1779             }
1780 #endif
1781           }                     //unread_msg_id
1782 
1783         }                       //CMTI well formatted
1784 
1785       }                         //CMTI
1786 
1787       if ((strncmp(p->line_array.result[i], "+MMGL:", 6) == 0)) {   //TODO MOTOROLA SMS FIXME in config!
1788         int err = 0;
1789         //int unread_msg_id=0;
1790 
1791         if (option_debug)
1792           DEBUGA_AT("|%s| +MMGL: Listing Motorola SMSs!\n", CELLIAX_P_LOG,
1793                     p->line_array.result[i]);
1794 
1795         err = sscanf(&p->line_array.result[i][7], "%d", &p->unread_sms_msg_id);
1796         if (err < 1) {
1797           ERRORA("|%s| is not formatted as: |+MMGL: xx|\n", CELLIAX_P_LOG,
1798                  p->line_array.result[i]);
1799         }
1800       }
1801       if ((strncmp(p->line_array.result[i], "+CMGL:", 6) == 0)) {   //TODO  SMS FIXME in config!
1802         if (option_debug)
1803           DEBUGA_AT("|%s| +CMGL: Listing SMSs!\n", CELLIAX_P_LOG,
1804                     p->line_array.result[i]);
1805       }
1806       if ((strncmp(p->line_array.result[i], "+MMGR:", 6) == 0)) {   //TODO MOTOROLA SMS FIXME in config!
1807         if (option_debug)
1808           DEBUGA_AT("|%s| +MMGR: Reading Motorola SMS!\n", CELLIAX_P_LOG,
1809                     p->line_array.result[i]);
1810         if (p->reading_sms_msg)
1811           p->reading_sms_msg++;
1812       }
1813       if ((strncmp(p->line_array.result[i], "+CMGR: \"STO U", 13) == 0)) {  //TODO  SMS FIXME in config!
1814         if (option_debug)
1815           DEBUGA_AT("|%s| +CMGR: Reading stored UNSENT SMS!\n", CELLIAX_P_LOG,
1816                     p->line_array.result[i]);
1817       } else if ((strncmp(p->line_array.result[i], "+CMGR: \"STO S", 13) == 0)) {   //TODO  SMS FIXME in config!
1818         if (option_debug)
1819           DEBUGA_AT("|%s| +CMGR: Reading stored SENT SMS!\n", CELLIAX_P_LOG,
1820                     p->line_array.result[i]);
1821       } else if ((strncmp(p->line_array.result[i], "+CMGR: \"REC R", 13) == 0)) {   //TODO  SMS FIXME in config!
1822         if (option_debug)
1823           DEBUGA_AT("|%s| +CMGR: Reading received READ SMS!\n", CELLIAX_P_LOG,
1824                     p->line_array.result[i]);
1825       } else if ((strncmp(p->line_array.result[i], "+CMGR: \"REC U", 13) == 0)) {   //TODO  SMS FIXME in config!
1826         if (option_debug)
1827           DEBUGA_AT("|%s| +CMGR: Reading received UNREAD SMS!\n", CELLIAX_P_LOG,
1828                     p->line_array.result[i]);
1829         if (p->reading_sms_msg)
1830           p->reading_sms_msg++;
1831       }
1832 
1833       if ((strcmp(p->line_array.result[i], "+MCST: 17") == 0)) {    /* motorola call processing unsolicited messages */
1834         p->phone_callflow = CALLFLOW_CALL_INFLUX;
1835         if (option_debug > 1)
1836           DEBUGA_AT("|%s| CALLFLOW_CALL_INFLUX\n", CELLIAX_P_LOG,
1837                     p->line_array.result[i]);
1838       }
1839 
1840       if ((strcmp(p->line_array.result[i], "+MCST: 68") == 0)) {    /* motorola call processing unsolicited messages */
1841         p->phone_callflow = CALLFLOW_CALL_NOSERVICE;
1842         if (option_debug > 1)
1843           DEBUGA_AT("|%s| CALLFLOW_CALL_NOSERVICE\n", CELLIAX_P_LOG,
1844                     p->line_array.result[i]);
1845         if (p->interface_state != AST_STATE_DOWN && p->owner) {
1846           p->owner->hangupcause = AST_CAUSE_FAILURE;
1847           celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
1848         }
1849       }
1850       if ((strcmp(p->line_array.result[i], "+MCST: 70") == 0)) {    /* motorola call processing unsolicited messages */
1851         p->phone_callflow = CALLFLOW_CALL_OUTGOINGRESTRICTED;
1852         if (option_debug > 1)
1853           DEBUGA_AT("|%s| CALLFLOW_CALL_OUTGOINGRESTRICTED\n", CELLIAX_P_LOG,
1854                     p->line_array.result[i]);
1855         if (p->interface_state != AST_STATE_DOWN && p->owner) {
1856           p->owner->hangupcause = AST_CAUSE_FAILURE;
1857           celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
1858         }
1859       }
1860       if ((strcmp(p->line_array.result[i], "+MCST: 72") == 0)) {    /* motorola call processing unsolicited messages */
1861         p->phone_callflow = CALLFLOW_CALL_SECURITYFAIL;
1862         if (option_debug > 1)
1863           DEBUGA_AT("|%s| CALLFLOW_CALL_SECURITYFAIL\n", CELLIAX_P_LOG,
1864                     p->line_array.result[i]);
1865         if (p->interface_state != AST_STATE_DOWN && p->owner) {
1866           p->owner->hangupcause = AST_CAUSE_FAILURE;
1867           celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
1868         }
1869       }
1870 
1871       if ((strncmp(p->line_array.result[i], "+CPBR", 5) == 0)) {    /* phonebook stuff begins */
1872 
1873         if (p->phonebook_querying) {    /* probably phonebook struct begins */
1874           int err, first_entry, last_entry, number_lenght, text_lenght;
1875 
1876           if (option_debug)
1877             DEBUGA_AT("phonebook struct: |%s|\n", CELLIAX_P_LOG, p->line_array.result[i]);
1878 
1879           err =
1880             sscanf(&p->line_array.result[i][8], "%d-%d),%d,%d", &first_entry, &last_entry,
1881                    &number_lenght, &text_lenght);
1882           if (err < 4) {
1883 
1884             err =
1885               sscanf(&p->line_array.result[i][7], "%d-%d,%d,%d", &first_entry,
1886                      &last_entry, &number_lenght, &text_lenght);
1887           }
1888 
1889           if (err < 4) {
1890             ERRORA
1891               ("phonebook struct: |%s| is nor formatted as: |+CPBR: (1-750),40,14| neither as: |+CPBR: 1-750,40,14|\n",
1892                CELLIAX_P_LOG, p->line_array.result[i]);
1893           } else {
1894 
1895             if (option_debug)
1896               DEBUGA_AT
1897                 ("First entry: %d, last entry: %d, phone number max lenght: %d, text max lenght: %d\n",
1898                  CELLIAX_P_LOG, first_entry, last_entry, number_lenght, text_lenght);
1899             p->phonebook_first_entry = first_entry;
1900             p->phonebook_last_entry = last_entry;
1901             p->phonebook_number_lenght = number_lenght;
1902             p->phonebook_text_lenght = text_lenght;
1903           }
1904 
1905         } else {                /* probably phonebook entry begins */
1906 
1907           if (p->phonebook_listing) {
1908             int err, entry_id, entry_type;
1909 
1910             char entry_number[256];
1911             char entry_text[256];
1912 
1913             if (option_debug)
1914               DEBUGA_AT("phonebook entry: |%s|\n", CELLIAX_P_LOG,
1915                         p->line_array.result[i]);
1916 
1917             err =
1918               sscanf(&p->line_array.result[i][7], "%d,\"%255[0-9+]\",%d,\"%255[^\"]\"",
1919                      &entry_id, entry_number, &entry_type, entry_text);
1920             if (err < 4) {
1921               ERRORA
1922                 ("err=%d, phonebook entry: |%s| is not formatted as: |+CPBR: 504,\"+39025458068\",145,\"ciao a tutti\"|\n",
1923                  CELLIAX_P_LOG, err, p->line_array.result[i]);
1924             } else {
1925               //TODO: sanitize entry_text
1926               if (option_debug)
1927                 DEBUGA_AT("Number: %s, Text: %s, Type: %d\n", CELLIAX_P_LOG, entry_number,
1928                           entry_text, entry_type);
1929               /* write entry in phonebook file */
1930               if (p->phonebook_writing_fp) {
1931                 celliax_dir_entry_extension++;
1932 
1933                 fprintf(p->phonebook_writing_fp,
1934                         "%s  => ,%sSKO,,,hidefromdir=%s|phonebook_direct_calling_ext=%d%s%.4d|phonebook_entry_fromcell=%s|phonebook_entry_owner=%s\n",
1935                         entry_number, entry_text, "no",
1936                         p->celliax_dir_entry_extension_prefix, "2",
1937                         celliax_dir_entry_extension, "yes", "not_specified");
1938                 fprintf(p->phonebook_writing_fp,
1939                         "%s  => ,%sDO,,,hidefromdir=%s|phonebook_direct_calling_ext=%d%s%.4d|phonebook_entry_fromcell=%s|phonebook_entry_owner=%s\n",
1940                         entry_number, entry_text, "no",
1941                         p->celliax_dir_entry_extension_prefix, "3",
1942                         celliax_dir_entry_extension, "yes", "not_specified");
1943               }
1944             }
1945 
1946           }
1947 
1948           if (p->phonebook_listing_received_calls) {
1949             int err, entry_id, entry_type;
1950 
1951             char entry_number[256] = "";
1952             char entry_text[256] = "";
1953 
1954             if (option_debug)
1955               DEBUGA_AT("phonebook entry: |%s|\n", CELLIAX_P_LOG,
1956                         p->line_array.result[i]);
1957 
1958             err =
1959               sscanf(&p->line_array.result[i][7], "%d,\"%255[0-9+]\",%d,\"%255[^\"]\"",
1960                      &entry_id, entry_number, &entry_type, entry_text);
1961             if (err < 1) {      //we match only on the progressive id, maybe the remote party has not sent its number, and/or there is no corresponding text entry in the phone directory
1962               ERRORA
1963                 ("err=%d, phonebook entry: |%s| is not formatted as: |+CPBR: 504,\"+39025458068\",145,\"ciao a tutti\"|\n",
1964                  CELLIAX_P_LOG, err, p->line_array.result[i]);
1965             } else {
1966               //TODO: sanitize entry_text
1967 
1968               if (option_debug)
1969                 DEBUGA_AT("Number: %s, Text: %s, Type: %d\n", CELLIAX_P_LOG, entry_number,
1970                           entry_text, entry_type);
1971               memset(p->callid_name, 0, sizeof(p->callid_name));
1972               memset(p->callid_number, 0, sizeof(p->callid_number));
1973               strncpy(p->callid_name, entry_text, sizeof(p->callid_name));
1974               strncpy(p->callid_number, entry_number, sizeof(p->callid_number));
1975               if (option_debug)
1976                 DEBUGA_AT("incoming callid: Text: %s, Number: %s\n", CELLIAX_P_LOG,
1977                           p->callid_name, p->callid_number);
1978 
1979               DEBUGA_AT("|%s| CPBR INCOMING CALLID: name is %s, number is %s\n",
1980                         CELLIAX_P_LOG, p->line_array.result[i],
1981                         p->callid_name[0] != 1 ? p->callid_name : "not available",
1982                         p->callid_number[0] ? p->callid_number : "not available");
1983 
1984               /* mark the time of RING */
1985               gettimeofday(&(p->ringtime), NULL);
1986               p->interface_state = AST_STATE_RING;
1987               p->phone_callflow = CALLFLOW_INCOMING_RING;
1988 
1989             }
1990 
1991           }
1992 
1993           else {
1994             DEBUGA_AT("phonebook entry: |%s|\n", CELLIAX_P_LOG, p->line_array.result[i]);
1995 
1996           }
1997         }
1998 
1999       }
2000 
2001       if ((strncmp(p->line_array.result[i], "*ECAV", 5) == 0) || (strncmp(p->line_array.result[i], "*ECAM", 5) == 0)) { /* sony-ericsson call processing unsolicited messages */
2002         int res, ccid, ccstatus, calltype, processid, exitcause, number, type;
2003         res = ccid = ccstatus = calltype = processid = exitcause = number = type = 0;
2004         res =
2005           sscanf(&p->line_array.result[i][6], "%d,%d,%d,%d,%d,%d,%d", &ccid, &ccstatus,
2006                  &calltype, &processid, &exitcause, &number, &type);
2007         /* only changes the phone_callflow if enought parameters were parsed */
2008         if (res >= 3) {
2009           switch (ccstatus) {
2010           case 0:
2011             if (p->owner) {
2012               ast_setstate(p->owner, AST_STATE_DOWN);
2013               p->owner->hangupcause = AST_CAUSE_NORMAL;
2014               celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
2015             }
2016             p->phone_callflow = CALLFLOW_CALL_IDLE;
2017             p->interface_state = AST_STATE_DOWN;
2018             if (option_debug > 1)
2019               DEBUGA_AT("|%s| Sony-Ericsson *ECAM/*ECAV: IDLE\n", CELLIAX_P_LOG,
2020                         p->line_array.result[i]);
2021             break;
2022           case 1:
2023             if (option_debug > 1)
2024               DEBUGA_AT("|%s| Sony-Ericsson *ECAM/*ECAV: CALLING\n", CELLIAX_P_LOG,
2025                         p->line_array.result[i]);
2026             break;
2027           case 2:
2028             if (p->owner) {
2029               ast_setstate(p->owner, AST_STATE_DIALING);
2030             }
2031             p->interface_state = CALLFLOW_CALL_DIALING;
2032             if (option_debug > 1)
2033               DEBUGA_AT("|%s| Sony-Ericsson *ECAM/*ECAV: CONNECTING\n", CELLIAX_P_LOG,
2034                         p->line_array.result[i]);
2035             break;
2036           case 3:
2037             if (p->owner) {
2038               ast_setstate(p->owner, AST_STATE_UP);
2039               celliax_queue_control(p->owner, AST_CONTROL_ANSWER);
2040             }
2041             p->phone_callflow = CALLFLOW_CALL_ACTIVE;
2042             p->interface_state = AST_STATE_UP;
2043             if (option_debug > 1)
2044               DEBUGA_AT("|%s| Sony-Ericsson *ECAM/*ECAV: ACTIVE\n", CELLIAX_P_LOG,
2045                         p->line_array.result[i]);
2046             break;
2047           case 4:
2048             if (option_debug > 1)
2049               DEBUGA_AT
2050                 ("|%s| Sony-Ericsson *ECAM/*ECAV: don't know how to handle HOLD event\n",
2051                  CELLIAX_P_LOG, p->line_array.result[i]);
2052             break;
2053           case 5:
2054             if (option_debug > 1)
2055               DEBUGA_AT
2056                 ("|%s| Sony-Ericsson *ECAM/*ECAV: don't know how to handle WAITING event\n",
2057                  CELLIAX_P_LOG, p->line_array.result[i]);
2058             break;
2059           case 6:
2060             if (option_debug > 1)
2061               DEBUGA_AT
2062                 ("|%s| Sony-Ericsson *ECAM/*ECAV: don't know how to handle ALERTING event\n",
2063                  CELLIAX_P_LOG, p->line_array.result[i]);
2064             break;
2065           case 7:
2066             if (p->owner) {
2067               ast_setstate(p->owner, AST_STATE_BUSY);
2068               celliax_queue_control(p->owner, AST_CONTROL_BUSY);
2069             }
2070             p->phone_callflow = CALLFLOW_CALL_LINEBUSY;
2071             p->interface_state = AST_STATE_BUSY;
2072             if (option_debug > 1)
2073               DEBUGA_AT("|%s| Sony-Ericsson *ECAM/*ECAV: BUSY\n", CELLIAX_P_LOG,
2074                         p->line_array.result[i]);
2075             break;
2076           }
2077         } else {
2078           if (option_debug > 1)
2079             DEBUGA_AT("|%s| Sony-Ericsson *ECAM/*ECAV: could not parse parameters\n",
2080                       CELLIAX_P_LOG, p->line_array.result[i]);
2081         }
2082 
2083       }
2084 
2085       /* at_indicator_* are unsolicited messages sent by the phone to signal us that some of its visual indicators on its screen has changed, based on CIND CMER ETSI docs */
2086       if ((strcmp(p->line_array.result[i], p->at_indicator_noservice_string) == 0)) {
2087         if (option_debug > 1)
2088           ERRORA("|%s| at_indicator_noservice_string\n", CELLIAX_P_LOG,
2089                  p->line_array.result[i]);
2090       }
2091 
2092       if ((strcmp(p->line_array.result[i], p->at_indicator_nosignal_string) == 0)) {
2093         if (option_debug > 1)
2094           ERRORA("|%s| at_indicator_nosignal_string\n", CELLIAX_P_LOG,
2095                  p->line_array.result[i]);
2096       }
2097 
2098       if ((strcmp(p->line_array.result[i], p->at_indicator_lowsignal_string) == 0)) {
2099         if (option_debug > 1)
2100           WARNINGA("|%s| at_indicator_lowsignal_string\n", CELLIAX_P_LOG,
2101                    p->line_array.result[i]);
2102       }
2103 
2104       if ((strcmp(p->line_array.result[i], p->at_indicator_lowbattchg_string) == 0)) {
2105         if (option_debug > 1)
2106           WARNINGA("|%s| at_indicator_lowbattchg_string\n", CELLIAX_P_LOG,
2107                    p->line_array.result[i]);
2108       }
2109 
2110       if ((strcmp(p->line_array.result[i], p->at_indicator_nobattchg_string) == 0)) {
2111         if (option_debug > 1)
2112           ERRORA("|%s| at_indicator_nobattchg_string\n", CELLIAX_P_LOG,
2113                  p->line_array.result[i]);
2114       }
2115 
2116       if ((strcmp(p->line_array.result[i], p->at_indicator_callactive_string) == 0)) {
2117         if (option_debug > 1)
2118           DEBUGA_AT("|%s| at_indicator_callactive_string\n", CELLIAX_P_LOG,
2119                     p->line_array.result[i]);
2120       }
2121 
2122       if ((strcmp(p->line_array.result[i], p->at_indicator_nocallactive_string) == 0)) {
2123         if (option_debug > 1)
2124           DEBUGA_AT("|%s| at_indicator_nocallactive_string\n", CELLIAX_P_LOG,
2125                     p->line_array.result[i]);
2126       }
2127 
2128       if ((strcmp(p->line_array.result[i], p->at_indicator_nocallsetup_string) == 0)) {
2129         if (option_debug > 1)
2130           DEBUGA_AT("|%s| at_indicator_nocallsetup_string\n", CELLIAX_P_LOG,
2131                     p->line_array.result[i]);
2132       }
2133 
2134       if ((strcmp(p->line_array.result[i], p->at_indicator_callsetupincoming_string) ==
2135            0)) {
2136         if (option_debug > 1)
2137           DEBUGA_AT("|%s| at_indicator_callsetupincoming_string\n", CELLIAX_P_LOG,
2138                     p->line_array.result[i]);
2139       }
2140 
2141       if ((strcmp(p->line_array.result[i], p->at_indicator_callsetupoutgoing_string) ==
2142            0)) {
2143         if (option_debug > 1)
2144           DEBUGA_AT("|%s| at_indicator_callsetupoutgoing_string\n", CELLIAX_P_LOG,
2145                     p->line_array.result[i]);
2146       }
2147 
2148       if ((strcmp(p->line_array.result[i], p->at_indicator_callsetupremoteringing_string)
2149            == 0)) {
2150         if (option_debug > 1)
2151           DEBUGA_AT("|%s| at_indicator_callsetupremoteringing_string\n", CELLIAX_P_LOG,
2152                     p->line_array.result[i]);
2153       }
2154 
2155     }
2156 
2157     /* let's look for OK, ERROR and EXPECTED_STRING in the complete lines read so far, without re-looking at the lines that has been yet looked at */
2158     for (i = la_read; i < la_counter; i++) {
2159       if (expected_string) {
2160         if ((strncmp(p->line_array.result[i], expected_string, strlen(expected_string))
2161              == 0)) {
2162           if (option_debug > 1)
2163             DEBUGA_AT("|%s| got what EXPECTED\n", CELLIAX_P_LOG, p->line_array.result[i]);
2164           at_ack = AT_OK;
2165         }
2166       } else {
2167         //if ((strcmp(p->line_array.result[i], "OK") == 0)) {
2168         if ((strcmp(p->line_array.result[i], "OK") == 0) || (strcmp(p->line_array.result[i], "NO CARRIER") == 0) ) {
2169           if (option_debug > 1)
2170             DEBUGA_AT("got OK\n", CELLIAX_P_LOG);
2171           at_ack = AT_OK;
2172         }
2173       }
2174       if ((strcmp(p->line_array.result[i], "ERROR") == 0)) {
2175         if (option_debug > 1)
2176           DEBUGA_AT("got ERROR\n", CELLIAX_P_LOG);
2177         at_ack = AT_ERROR;
2178       }
2179 
2180       /* if we are reading an sms message from memory, put the line into the sms buffer if the line is not "OK" or "ERROR" */
2181       if (p->reading_sms_msg > 1 && at_ack == -1) {
2182         int c;
2183         char sms_body[16000];
2184         int err;
2185 
2186         if (strncmp(p->line_array.result[i], "+CMGR", 5) == 0) {    /* we are reading the "header" of an SMS */
2187           char content[512];
2188           char content2[512];
2189 
2190           memset(content, '\0', sizeof(content));
2191 
2192           int inside_comma = 0;
2193           int inside_quote = 0;
2194           int d = 0;
2195 
2196           for (c = 0; c < strlen(p->line_array.result[i]); c++) {
2197             if (p->line_array.result[i][c] == ','
2198                 && p->line_array.result[i][c - 1] != '\\' && inside_quote == 0) {
2199               if (inside_comma) {
2200                 inside_comma = 0;
2201                 //NOTICA("inside_comma=%d, inside_quote=%d, we're at=%s\n", CELLIAX_P_LOG, inside_comma, inside_quote, &p->line_array.result[i][c]);
2202               } else {
2203                 inside_comma = 1;
2204                 //NOTICA("inside_comma=%d, inside_quote=%d, we're at=%s\n", CELLIAX_P_LOG, inside_comma, inside_quote, &p->line_array.result[i][c]);
2205               }
2206             }
2207             if (p->line_array.result[i][c] == '"'
2208                 && p->line_array.result[i][c - 1] != '\\') {
2209               if (inside_quote) {
2210                 inside_quote = 0;
2211                 //ERRORA("END_CONTENT inside_comma=%d, inside_quote=%d, we're at=%s\n", CELLIAX_P_LOG, inside_comma, inside_quote, &p->line_array.result[i][c]);
2212                 DEBUGA_AT("content=%s\n", CELLIAX_P_LOG, content);
2213 
2214                 strncat(p->sms_message, "---",
2215                         ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2216                 strncat(p->sms_message, content,
2217                         ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2218                 strncat(p->sms_message, "|||",
2219                         ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2220 
2221                 memset(content2, '\0', sizeof(content2));
2222                 err = ucs2_to_utf8(p, content, content2, sizeof(content2));
2223 
2224                 strncat(p->sms_message, "---",
2225                         ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2226                 if (!err)
2227                   strncat(p->sms_message, content2,
2228                           ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2229                 strncat(p->sms_message, "|||",
2230                         ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2231                 memset(content, '\0', sizeof(content));
2232                 d = 0;
2233               } else {
2234                 inside_quote = 1;
2235                 //WARNINGA("START_CONTENT inside_comma=%d, inside_quote=%d, we're at=%s\n", CELLIAX_P_LOG, inside_comma, inside_quote, &p->line_array.result[i][c]);
2236               }
2237             }
2238             if (inside_quote && p->line_array.result[i][c] != '"') {
2239 
2240               content[d] = p->line_array.result[i][c];
2241               d++;
2242 
2243             }
2244 
2245           }
2246         }                       //it was the +CMGR answer from the cellphone
2247         else {
2248           strncat(p->sms_message, "---",
2249                   ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2250           strncat(p->sms_message, p->line_array.result[i],
2251                   ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2252           strncat(p->sms_message, "|||",
2253                   ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2254 
2255           memset(sms_body, '\0', sizeof(sms_body));
2256           err = ucs2_to_utf8(p, p->line_array.result[i], sms_body, sizeof(sms_body));
2257 
2258           strncat(p->sms_message, "---",
2259                   ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2260           if (!err)
2261             strncat(p->sms_message, sms_body,
2262                     ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2263           strncat(p->sms_message, "|||",
2264                   ((sizeof(p->sms_message) - strlen(p->sms_message)) - 1));
2265 
2266           DEBUGA_AT("sms_message=%s\n", CELLIAX_P_LOG, p->sms_message);
2267 
2268         }                       //it was the UCS2 from cellphone
2269 
2270       }                         //we were reading the SMS
2271 
2272     }
2273 
2274     la_read = la_counter;
2275 
2276     if (look_for_ack && at_ack > -1)
2277       break;
2278 
2279     if (la_counter > AT_MESG_MAX_LINES) {
2280       ERRORA("Too many lines in result (>%d). Stopping reader.\n", CELLIAX_P_LOG,
2281              AT_MESG_MAX_LINES);
2282       at_ack = AT_ERROR;
2283       break;
2284     }
2285   }
2286 
2287   UNLOCKA(&p->controldev_lock);
2288   POPPA_UNLOCKA(&p->controldev_lock);
2289   if (select_err == -1) {
2290     ERRORA("select returned -1 on %s, setting controldev_dead, error was: %s\n",
2291            CELLIAX_P_LOG, p->controldevice_name, strerror(errno));
2292     p->controldev_dead = 1;
2293     close(p->controldevfd);
2294     if (p->owner)
2295       celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
2296     return -1;
2297   }
2298 
2299   if (p->phone_callflow == CALLFLOW_CALL_INCOMING && p->call_incoming_time.tv_sec) {    //after three sec of CALLFLOW_CALL_INCOMING, we assume the phone is incapable of notifying RING (eg: motorola c350), so we try to answer
2300     char list_command[64];
2301     struct timeval call_incoming_timeout;
2302     gettimeofday(&call_incoming_timeout, NULL);
2303     call_incoming_timeout.tv_sec -= 3;
2304     DEBUGA_AT
2305       ("CALLFLOW_CALL_INCOMING call_incoming_time.tv_sec=%ld, call_incoming_timeout.tv_sec=%ld\n",
2306        CELLIAX_P_LOG, p->call_incoming_time.tv_sec, call_incoming_timeout.tv_sec);
2307     if (call_incoming_timeout.tv_sec > p->call_incoming_time.tv_sec) {
2308 
2309       p->call_incoming_time.tv_sec = 0;
2310       p->call_incoming_time.tv_usec = 0;
2311       DEBUGA_AT
2312         ("CALLFLOW_CALL_INCOMING call_incoming_time.tv_sec=%ld, call_incoming_timeout.tv_sec=%ld\n",
2313          CELLIAX_P_LOG, p->call_incoming_time.tv_sec, call_incoming_timeout.tv_sec);
2314       res = celliax_serial_write_AT_ack(p, "AT+CPBS=RC");
2315       if (res) {
2316         ERRORA
2317           ("AT+CPBS=RC (select memory of received calls) was not answered by the phone\n",
2318            CELLIAX_P_LOG);
2319       }
2320       p->phonebook_querying = 1;
2321       res = celliax_serial_write_AT_ack(p, "AT+CPBR=?");
2322       if (res) {
2323         ERRORA
2324           ("AT+CPBS=RC (select memory of received calls) was not answered by the phone\n",
2325            CELLIAX_P_LOG);
2326       }
2327       p->phonebook_querying = 0;
2328       sprintf(list_command, "AT+CPBR=%d,%d", p->phonebook_first_entry,
2329               p->phonebook_last_entry);
2330       p->phonebook_listing_received_calls = 1;
2331       res = celliax_serial_write_AT_expect_longtime(p, list_command, "OK");
2332       if (res) {
2333         WARNINGA("AT+CPBR=%d,%d failed, continue\n", CELLIAX_P_LOG,
2334                  p->phonebook_first_entry, p->phonebook_last_entry);
2335       }
2336       p->phonebook_listing_received_calls = 0;
2337     }
2338   }
2339 
2340   if (p->phone_callflow == CALLFLOW_INCOMING_RING) {
2341     struct timeval call_incoming_timeout;
2342     gettimeofday(&call_incoming_timeout, NULL);
2343     call_incoming_timeout.tv_sec -= 10;
2344     DEBUGA_AT
2345       ("CALLFLOW_CALL_INCOMING call_incoming_time.tv_sec=%ld, call_incoming_timeout.tv_sec=%ld\n",
2346        CELLIAX_P_LOG, p->call_incoming_time.tv_sec, call_incoming_timeout.tv_sec);
2347     if (call_incoming_timeout.tv_sec > p->ringtime.tv_sec) {
2348       ERRORA("Ringing stopped and I have not answered. Why?\n", CELLIAX_P_LOG);
2349       DEBUGA_AT
2350         ("CALLFLOW_CALL_INCOMING call_incoming_time.tv_sec=%ld, call_incoming_timeout.tv_sec=%ld\n",
2351          CELLIAX_P_LOG, p->call_incoming_time.tv_sec, call_incoming_timeout.tv_sec);
2352       if (p->owner) {
2353         celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
2354         p->owner->hangupcause = AST_CAUSE_FAILURE;
2355       }
2356     }
2357   }
2358   p->line_array.elemcount = la_counter;
2359   //NOTICA (" OUTSIDE this celliax_serial_device %s \n", CELLIAX_P_LOG, p->controldevice_name);
2360   if (look_for_ack)
2361     return at_ack;
2362   else
2363     return 0;
2364 }
2365 
celliax_serial_write_AT(struct celliax_pvt * p,const char * data)2366 int celliax_serial_write_AT(struct celliax_pvt *p, const char *data)
2367 {
2368   int howmany;
2369   int i;
2370   int res;
2371   int count;
2372 
2373   howmany = strlen(data);
2374 
2375   for (i = 0; i < howmany; i++) {
2376     res = write(p->controldevfd, &data[i], 1);
2377 
2378     if (res != 1) {
2379       DEBUGA_AT("Error sending (%.1s): %d (%s)\n", CELLIAX_P_LOG, &data[i], res,
2380                 strerror(errno));
2381       usleep(100000);
2382       for (count = 0; count < 10; count++) {
2383         res = write(p->controldevfd, &data[i], 1);
2384         if (res == 1) {
2385           DEBUGA_AT("Successfully RE-sent (%.1s): %d %d (%s)\n", CELLIAX_P_LOG, &data[i],
2386                     count, res, strerror(errno));
2387           break;
2388         } else
2389           DEBUGA_AT("Error RE-sending (%.1s): %d %d (%s)\n", CELLIAX_P_LOG, &data[i],
2390                     count, res, strerror(errno));
2391         usleep(100000);
2392 
2393       }
2394       if (res != 1) {
2395         ERRORA("Error RE-sending (%.1s): %d %d (%s)\n", CELLIAX_P_LOG, &data[i], count,
2396                res, strerror(errno));
2397         return -1;
2398       }
2399     }
2400     if (option_debug > 1)
2401       DEBUGA_AT("sent data... (%.1s)\n", CELLIAX_P_LOG, &data[i]);
2402     usleep(1000);               /* release the cpu */
2403   }
2404 
2405   res = write(p->controldevfd, "\r", 1);
2406 
2407   if (res != 1) {
2408     DEBUGA_AT("Error sending (carriage return): %d (%s)\n", CELLIAX_P_LOG, res,
2409               strerror(errno));
2410     usleep(100000);
2411     for (count = 0; count < 10; count++) {
2412       res = write(p->controldevfd, "\r", 1);
2413 
2414       if (res == 1) {
2415         DEBUGA_AT("Successfully RE-sent carriage return: %d %d (%s)\n", CELLIAX_P_LOG,
2416                   count, res, strerror(errno));
2417         break;
2418       } else
2419         DEBUGA_AT("Error RE-sending (carriage return): %d %d (%s)\n", CELLIAX_P_LOG,
2420                   count, res, strerror(errno));
2421       usleep(100000);
2422 
2423     }
2424     if (res != 1) {
2425       ERRORA("Error RE-sending (carriage return): %d %d (%s)\n", CELLIAX_P_LOG, count,
2426              res, strerror(errno));
2427       return -1;
2428     }
2429   }
2430   if (option_debug > 1)
2431     DEBUGA_AT("sent (carriage return)\n", CELLIAX_P_LOG);
2432   usleep(1000);                 /* release the cpu */
2433 
2434   return howmany;
2435 }
2436 
celliax_serial_write_AT_nocr(struct celliax_pvt * p,const char * data)2437 int celliax_serial_write_AT_nocr(struct celliax_pvt *p, const char *data)
2438 {
2439   int howmany;
2440   int i;
2441   int res;
2442   int count;
2443 
2444   howmany = strlen(data);
2445 
2446   for (i = 0; i < howmany; i++) {
2447     res = write(p->controldevfd, &data[i], 1);
2448 
2449     if (res != 1) {
2450       DEBUGA_AT("Error sending (%.1s): %d (%s)\n", CELLIAX_P_LOG, &data[i], res,
2451                 strerror(errno));
2452       usleep(100000);
2453       for (count = 0; count < 10; count++) {
2454         res = write(p->controldevfd, &data[i], 1);
2455         if (res == 1)
2456           break;
2457         else
2458           DEBUGA_AT("Error RE-sending (%.1s): %d %d (%s)\n", CELLIAX_P_LOG, &data[i],
2459                     count, res, strerror(errno));
2460         usleep(100000);
2461 
2462       }
2463       if (res != 1) {
2464         ERRORA("Error RE-sending (%.1s): %d %d (%s)\n", CELLIAX_P_LOG, &data[i], count,
2465                res, strerror(errno));
2466         return -1;
2467       }
2468     }
2469     if (option_debug > 1)
2470       DEBUGA_AT("sent data... (%.1s)\n", CELLIAX_P_LOG, &data[i]);
2471     usleep(1000);               /* release the cpu */
2472   }
2473 
2474   usleep(1000);                 /* release the cpu */
2475 
2476   return howmany;
2477 }
2478 
celliax_serial_write_AT_noack(struct celliax_pvt * p,const char * data)2479 int celliax_serial_write_AT_noack(struct celliax_pvt *p, const char *data)
2480 {
2481 
2482   if (option_debug > 1)
2483     DEBUGA_AT("celliax_serial_write_AT_noack: %s\n", CELLIAX_P_LOG, data);
2484 
2485   PUSHA_UNLOCKA(&p->controldev_lock);
2486   LOKKA(&p->controldev_lock);
2487   if (celliax_serial_write_AT(p, data) != strlen(data)) {
2488 
2489     ERRORA("Error sending data... (%s)\n", CELLIAX_P_LOG, strerror(errno));
2490     UNLOCKA(&p->controldev_lock);
2491     return -1;
2492   }
2493   UNLOCKA(&p->controldev_lock);
2494   POPPA_UNLOCKA(&p->controldev_lock);
2495 
2496   return 0;
2497 }
2498 
celliax_serial_write_AT_ack(struct celliax_pvt * p,const char * data)2499 int celliax_serial_write_AT_ack(struct celliax_pvt *p, const char *data)
2500 {
2501   int at_result = AT_ERROR;
2502 
2503   PUSHA_UNLOCKA(&p->controldev_lock);
2504   LOKKA(&p->controldev_lock);
2505   if (option_debug > 1)
2506     DEBUGA_AT("sending: %s\n", CELLIAX_P_LOG, data);
2507   if (celliax_serial_write_AT(p, data) != strlen(data)) {
2508     ERRORA("Error sending data... (%s) \n", CELLIAX_P_LOG, strerror(errno));
2509     UNLOCKA(&p->controldev_lock);
2510     return -1;
2511   }
2512 
2513   at_result = celliax_serial_read_AT(p, 1, 500000, 2, NULL, 1); // 2.5 sec timeout
2514   UNLOCKA(&p->controldev_lock);
2515   POPPA_UNLOCKA(&p->controldev_lock);
2516 
2517   return at_result;
2518 
2519 }
2520 
celliax_serial_write_AT_ack_nocr_longtime(struct celliax_pvt * p,const char * data)2521 int celliax_serial_write_AT_ack_nocr_longtime(struct celliax_pvt *p, const char *data)
2522 {
2523   int at_result = AT_ERROR;
2524 
2525   PUSHA_UNLOCKA(&p->controldev_lock);
2526   LOKKA(&p->controldev_lock);
2527   if (option_debug > 1)
2528     DEBUGA_AT("sending: %s\n", CELLIAX_P_LOG, data);
2529   if (celliax_serial_write_AT_nocr(p, data) != strlen(data)) {
2530     ERRORA("Error sending data... (%s) \n", CELLIAX_P_LOG, strerror(errno));
2531     UNLOCKA(&p->controldev_lock);
2532     return -1;
2533   }
2534 
2535   at_result = celliax_serial_read_AT(p, 1, 500000, 20, NULL, 1);    // 20.5 sec timeout
2536   UNLOCKA(&p->controldev_lock);
2537   POPPA_UNLOCKA(&p->controldev_lock);
2538 
2539   return at_result;
2540 
2541 }
2542 
celliax_serial_write_AT_expect1(struct celliax_pvt * p,const char * data,const char * expected_string,int expect_crlf,int seconds)2543 int celliax_serial_write_AT_expect1(struct celliax_pvt *p, const char *data,
2544                                     const char *expected_string, int expect_crlf,
2545                                     int seconds)
2546 {
2547   int at_result = AT_ERROR;
2548 
2549   PUSHA_UNLOCKA(&p->controldev_lock);
2550   LOKKA(&p->controldev_lock);
2551   if (option_debug > 1)
2552     DEBUGA_AT("sending: %s, expecting: %s\n", CELLIAX_P_LOG, data, expected_string);
2553   if (celliax_serial_write_AT(p, data) != strlen(data)) {
2554     ERRORA("Error sending data... (%s) \n", CELLIAX_P_LOG, strerror(errno));
2555     UNLOCKA(&p->controldev_lock);
2556     return -1;
2557   }
2558 
2559   at_result = celliax_serial_read_AT(p, 1, 500000, seconds, expected_string, expect_crlf);  // 20.5 sec timeout, used for querying the SIM and sending SMSs
2560   UNLOCKA(&p->controldev_lock);
2561   POPPA_UNLOCKA(&p->controldev_lock);
2562 
2563   return at_result;
2564 
2565 }
2566 
celliax_serial_AT_expect(struct celliax_pvt * p,const char * expected_string,int expect_crlf,int seconds)2567 int celliax_serial_AT_expect(struct celliax_pvt *p, const char *expected_string,
2568                              int expect_crlf, int seconds)
2569 {
2570   int at_result = AT_ERROR;
2571 
2572   PUSHA_UNLOCKA(&p->controldev_lock);
2573   LOKKA(&p->controldev_lock);
2574   if (option_debug > 1)
2575     DEBUGA_AT("expecting: %s\n", CELLIAX_P_LOG, expected_string);
2576 
2577   at_result = celliax_serial_read_AT(p, 1, 500000, seconds, expected_string, expect_crlf);  // 20.5 sec timeout, used for querying the SIM and sending SMSs
2578   UNLOCKA(&p->controldev_lock);
2579   POPPA_UNLOCKA(&p->controldev_lock);
2580 
2581   return at_result;
2582 
2583 }
2584 
celliax_serial_answer_AT(struct celliax_pvt * p)2585 int celliax_serial_answer_AT(struct celliax_pvt *p)
2586 {
2587   int res;
2588 
2589   res = celliax_serial_write_AT_expect(p, p->at_answer, p->at_answer_expect);
2590   if (res) {
2591     DEBUGA_AT
2592       ("at_answer command failed, command used: %s, expecting: %s, trying with AT+CKPD=\"S\"\n",
2593        CELLIAX_P_LOG, p->at_answer, p->at_answer_expect);
2594 
2595     res = celliax_serial_write_AT_ack(p, "AT+CKPD=\"S\"");
2596     if (res) {
2597       ERRORA("at_answer command failed, command used: 'AT+CKPD=\"S\"', giving up\n",
2598              CELLIAX_P_LOG);
2599       return -1;
2600     }
2601   }
2602   //p->interface_state = AST_STATE_UP;
2603   //p->phone_callflow = CALLFLOW_CALL_ACTIVE;
2604   DEBUGA_AT("AT: call answered\n", CELLIAX_P_LOG);
2605   return 0;
2606 }
2607 
celliax_serial_hangup_AT(struct celliax_pvt * p)2608 int celliax_serial_hangup_AT(struct celliax_pvt *p)
2609 {
2610   int res;
2611 
2612   if (p->interface_state != AST_STATE_DOWN) {
2613     res = celliax_serial_write_AT_expect(p, p->at_hangup, p->at_hangup_expect);
2614     if (res) {
2615       DEBUGA_AT
2616         ("at_hangup command failed, command used: %s, trying to use AT+CKPD=\"EEE\"\n",
2617          CELLIAX_P_LOG, p->at_hangup);
2618       res = celliax_serial_write_AT_ack(p, "AT+CKPD=\"EEE\"");
2619       if (res) {
2620         ERRORA("at_hangup command failed, command used: 'AT+CKPD=\"EEE\"'\n",
2621                CELLIAX_P_LOG);
2622         return -1;
2623       }
2624     }
2625   }
2626   p->interface_state = AST_STATE_DOWN;
2627   p->phone_callflow = CALLFLOW_CALL_IDLE;
2628   return 0;
2629 }
2630 
celliax_serial_config_AT(struct celliax_pvt * p)2631 int celliax_serial_config_AT(struct celliax_pvt *p)
2632 {
2633   int res;
2634 
2635 /* initial_pause? */
2636   if (p->at_initial_pause) {
2637     DEBUGA_AT("sleeping for %d usec\n", CELLIAX_P_LOG, p->at_initial_pause);
2638     usleep(p->at_initial_pause);
2639   }
2640 
2641 /* go until first empty preinit string, or last preinit string */
2642   while (1) {
2643 
2644     if (strlen(p->at_preinit_1)) {
2645       res = celliax_serial_write_AT_expect(p, p->at_preinit_1, p->at_preinit_1_expect);
2646       if (res) {
2647         DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2648                   p->at_preinit_1, p->at_preinit_1_expect);
2649       }
2650     } else {
2651       break;
2652     }
2653 
2654     if (strlen(p->at_preinit_2)) {
2655       res = celliax_serial_write_AT_expect(p, p->at_preinit_2, p->at_preinit_2_expect);
2656       if (res) {
2657         DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2658                   p->at_preinit_2, p->at_preinit_2_expect);
2659       }
2660     } else {
2661       break;
2662     }
2663 
2664     if (strlen(p->at_preinit_3)) {
2665       res = celliax_serial_write_AT_expect(p, p->at_preinit_3, p->at_preinit_3_expect);
2666       if (res) {
2667         DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2668                   p->at_preinit_3, p->at_preinit_3_expect);
2669       }
2670     } else {
2671       break;
2672     }
2673 
2674     if (strlen(p->at_preinit_4)) {
2675       res = celliax_serial_write_AT_expect(p, p->at_preinit_4, p->at_preinit_4_expect);
2676       if (res) {
2677         DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2678                   p->at_preinit_4, p->at_preinit_4_expect);
2679       }
2680     } else {
2681       break;
2682     }
2683 
2684     if (strlen(p->at_preinit_5)) {
2685       res = celliax_serial_write_AT_expect(p, p->at_preinit_5, p->at_preinit_5_expect);
2686       if (res) {
2687         DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2688                   p->at_preinit_5, p->at_preinit_5_expect);
2689       }
2690     } else {
2691       break;
2692     }
2693 
2694     break;
2695   }
2696 
2697 /* after_preinit_pause? */
2698   if (p->at_after_preinit_pause) {
2699     DEBUGA_AT("sleeping for %d usec\n", CELLIAX_P_LOG, p->at_after_preinit_pause);
2700     usleep(p->at_after_preinit_pause);
2701   }
2702 
2703   /* phone, brother, art you alive? */
2704   res = celliax_serial_write_AT_ack(p, "AT");
2705   if (res) {
2706     ERRORA("no response to AT\n", CELLIAX_P_LOG);
2707     return -1;
2708   }
2709   /* for motorola, bring it back to "normal" mode if it happens to be in another mode */
2710   res = celliax_serial_write_AT_ack(p, "AT+mode=0");
2711   if (res) {
2712     DEBUGA_AT("AT+mode=0 does not get OK from the phone. If it is NOT Motorola,"
2713               " no problem.\n", CELLIAX_P_LOG);
2714   }
2715   usleep(50000);
2716   /* for motorola end */
2717 
2718   /* reset AT configuration to phone default */
2719   res = celliax_serial_write_AT_ack(p, "ATZ");
2720   if (res) {
2721     DEBUGA_AT("ATZ failed\n", CELLIAX_P_LOG);
2722   }
2723 
2724   /* disable AT command echo */
2725   res = celliax_serial_write_AT_ack(p, "ATE0");
2726   if (res) {
2727     DEBUGA_AT("ATE0 failed\n", CELLIAX_P_LOG);
2728   }
2729 
2730   /* disable extended error reporting */
2731   res = celliax_serial_write_AT_ack(p, "AT+CMEE=0");
2732   if (res) {
2733     DEBUGA_AT("AT+CMEE failed\n", CELLIAX_P_LOG);
2734   }
2735 
2736   /* various phone manufacturer identifier */
2737   char at_command[5];
2738   int i;
2739   for (i = 0; i < 10; i++) {
2740     memset(at_command, 0, sizeof(at_command));
2741     sprintf(at_command, "ATI%d", i);
2742     res = celliax_serial_write_AT_ack(p, at_command);
2743     if (res) {
2744       DEBUGA_AT("ATI%d command failed, continue\n", CELLIAX_P_LOG, i);
2745     }
2746   }
2747 
2748   /* phone manufacturer */
2749   res = celliax_serial_write_AT_ack(p, "AT+CGMI");
2750   if (res) {
2751     DEBUGA_AT("AT+CGMI failed\n", CELLIAX_P_LOG);
2752   }
2753 
2754   /* phone model */
2755   res = celliax_serial_write_AT_ack(p, "AT+CGMM");
2756   if (res) {
2757     DEBUGA_AT("AT+CGMM failed\n", CELLIAX_P_LOG);
2758   }
2759 
2760   res = celliax_serial_write_AT_ack(p, "AT+CGSN");
2761   if (res) {
2762     DEBUGA_AT("AT+CGSN failed\n", CELLIAX_P_LOG);
2763   }
2764 
2765 /* this take a lot of time to complete on devices with slow serial link (eg.: 9600bps) */
2766 #if 0
2767   /* ask for the list of supported AT commands, useful to implement new models and debugging */
2768   res = celliax_serial_write_AT_ack(p, "AT+CLAC");
2769   if (res) {
2770     DEBUGA_AT("AT+CLAC failed, continue\n", CELLIAX_P_LOG);
2771   }
2772 #endif
2773   /* signal incoming SMS with a +CMTI unsolicited msg */
2774   res = celliax_serial_write_AT_ack(p, "AT+CNMI=3,1,0,0,0");
2775   if (res) {
2776     DEBUGA_AT("AT+CNMI=3,1,0,0,0 failed, continue\n", CELLIAX_P_LOG);
2777     p->sms_cnmi_not_supported = 1;
2778     p->celliax_serial_sync_period = 30;
2779   }
2780   /* what is the Message Center address (number) to which the SMS has to be sent? */
2781   res = celliax_serial_write_AT_ack(p, "AT+CSCA?");
2782   if (res) {
2783     DEBUGA_AT("AT+CSCA? failed, continue\n", CELLIAX_P_LOG);
2784   }
2785   /* what is the Message Format of SMSs? */
2786   res = celliax_serial_write_AT_ack(p, "AT+CMGF?");
2787   if (res) {
2788     DEBUGA_AT("AT+CMGF? failed, continue\n", CELLIAX_P_LOG);
2789   }
2790   res = celliax_serial_write_AT_ack(p, "AT+CMGF=1");    //TODO: support phones that only accept pdu mode
2791   if (res) {
2792     ERRORA("Error setting SMS sending mode to TEXT on the cellphone\n", CELLIAX_P_LOG);
2793     return RESULT_FAILURE;
2794   }
2795   /* what is the Charset of SMSs? */
2796   res = celliax_serial_write_AT_ack(p, "AT+CSCS?");
2797   if (res) {
2798     DEBUGA_AT("AT+CSCS? failed, continue\n", CELLIAX_P_LOG);
2799   }
2800 
2801   p->no_ucs2 = 0;
2802   res = celliax_serial_write_AT_ack(p, "AT+CSCS=\"UCS2\"");
2803   if (res) {
2804     WARNINGA
2805       ("AT+CSCS=\"UCS2\" (set TE messages to ucs2)  do not got OK from the phone, let's try with 'GSM'\n",
2806        CELLIAX_P_LOG);
2807     p->no_ucs2 = 1;
2808   }
2809 
2810   if (p->no_ucs2) {
2811     res = celliax_serial_write_AT_ack(p, "AT+CSCS=\"GSM\"");
2812     if (res) {
2813       WARNINGA("AT+CSCS=\"GSM\" (set TE messages to GSM)  do not got OK from the phone\n",
2814                CELLIAX_P_LOG);
2815     }
2816     //res = celliax_serial_write_AT_ack(p, "AT+CSMP=17,167,0,16"); //"flash", class 0  sms 7 bit
2817     res = celliax_serial_write_AT_ack(p, "AT+CSMP=17,167,0,0"); //normal, 7 bit message
2818     if (res) {
2819       WARNINGA("AT+CSMP do not got OK from the phone, continuing\n", CELLIAX_P_LOG);
2820     }
2821   } else {
2822     //res = celliax_serial_write_AT_ack(p, "AT+CSMP=17,167,0,20"); //"flash", class 0 sms 16 bit unicode
2823     res = celliax_serial_write_AT_ack(p, "AT+CSMP=17,167,0,8"); //unicode, 16 bit message
2824     if (res) {
2825       WARNINGA("AT+CSMP do not got OK from the phone, continuing\n", CELLIAX_P_LOG);
2826     }
2827   }
2828 
2829   /* is the unsolicited reporting of mobile equipment event supported? */
2830   res = celliax_serial_write_AT_ack(p, "AT+CMER=?");
2831   if (res) {
2832     DEBUGA_AT("AT+CMER=? failed, continue\n", CELLIAX_P_LOG);
2833   }
2834   /* request unsolicited reporting of mobile equipment indicators' events, to be screened by categories reported by +CIND=? */
2835   res = celliax_serial_write_AT_ack(p, "AT+CMER=3,0,0,1");
2836   if (res) {
2837     DEBUGA_AT("AT+CMER=? failed, continue\n", CELLIAX_P_LOG);
2838   }
2839 
2840   /* is the solicited reporting of mobile equipment indications supported? */
2841 
2842   res = celliax_serial_write_AT_ack(p, "AT+CIND=?");
2843   if (res) {
2844     DEBUGA_AT("AT+CIND=? failed, continue\n", CELLIAX_P_LOG);
2845   }
2846 
2847   /* is the unsolicited reporting of call monitoring supported? sony-ericsson specific */
2848   res = celliax_serial_write_AT_ack(p, "AT*ECAM=?");
2849   if (res) {
2850     DEBUGA_AT("AT*ECAM=? failed, continue\n", CELLIAX_P_LOG);
2851   }
2852   /* enable the unsolicited reporting of call monitoring. sony-ericsson specific */
2853   res = celliax_serial_write_AT_ack(p, "AT*ECAM=1");
2854   if (res) {
2855     DEBUGA_AT("AT*ECAM=1 failed, continue\n", CELLIAX_P_LOG);
2856     p->at_has_ecam = 0;
2857   } else {
2858     p->at_has_ecam = 1;
2859   }
2860 
2861   /* disable unsolicited signaling of call list */
2862   res = celliax_serial_write_AT_ack(p, "AT+CLCC=0");
2863   if (res) {
2864     DEBUGA_AT("AT+CLCC=0 failed, continue\n", CELLIAX_P_LOG);
2865     p->at_has_clcc = 0;
2866   } else {
2867     p->at_has_clcc = 1;
2868   }
2869 
2870   /* give unsolicited caller id when incoming call */
2871   res = celliax_serial_write_AT_ack(p, "AT+CLIP=1");
2872   if (res) {
2873     DEBUGA_AT("AT+CLIP failed, continue\n", CELLIAX_P_LOG);
2874   }
2875   /* for motorola */
2876   res = celliax_serial_write_AT_ack(p, "AT+MCST=1");    /* motorola call control codes
2877                                                            (to know when call is disconnected (they
2878                                                            don't give you "no carrier") */
2879   if (res) {
2880     DEBUGA_AT("AT+MCST=1 does not get OK from the phone. If it is NOT Motorola,"
2881               " no problem.\n", CELLIAX_P_LOG);
2882   }
2883   /* for motorola end */
2884 
2885 /* go until first empty postinit string, or last postinit string */
2886   while (1) {
2887 
2888     if (strlen(p->at_postinit_1)) {
2889       res = celliax_serial_write_AT_expect(p, p->at_postinit_1, p->at_postinit_1_expect);
2890       if (res) {
2891         DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2892                   p->at_postinit_1, p->at_postinit_1_expect);
2893       }
2894     } else {
2895       break;
2896     }
2897 
2898     if (strlen(p->at_postinit_2)) {
2899       res = celliax_serial_write_AT_expect(p, p->at_postinit_2, p->at_postinit_2_expect);
2900       if (res) {
2901         DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2902                   p->at_postinit_2, p->at_postinit_2_expect);
2903       }
2904     } else {
2905       break;
2906     }
2907 
2908     if (strlen(p->at_postinit_3)) {
2909       res = celliax_serial_write_AT_expect(p, p->at_postinit_3, p->at_postinit_3_expect);
2910       if (res) {
2911         DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2912                   p->at_postinit_3, p->at_postinit_3_expect);
2913       }
2914     } else {
2915       break;
2916     }
2917 
2918     if (strlen(p->at_postinit_4)) {
2919       res = celliax_serial_write_AT_expect(p, p->at_postinit_4, p->at_postinit_4_expect);
2920       if (res) {
2921         DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2922                   p->at_postinit_4, p->at_postinit_4_expect);
2923       }
2924     } else {
2925       break;
2926     }
2927 
2928     if (strlen(p->at_postinit_5)) {
2929       res = celliax_serial_write_AT_expect(p, p->at_postinit_5, p->at_postinit_5_expect);
2930       if (res) {
2931         DEBUGA_AT("%s does not get %s from the phone. Continuing.\n", CELLIAX_P_LOG,
2932                   p->at_postinit_5, p->at_postinit_5_expect);
2933       }
2934     } else {
2935       break;
2936     }
2937 
2938     break;
2939   }
2940 
2941   return 0;
2942 }
2943 
celliax_serial_call_AT(struct celliax_pvt * p,char * dstr)2944 int celliax_serial_call_AT(struct celliax_pvt *p, char *dstr)
2945 {
2946   int res;
2947   char at_command[256];
2948 
2949   if (option_debug)
2950     DEBUGA_PBX("Dialing %s\n", CELLIAX_P_LOG, dstr);
2951   memset(at_command, 0, sizeof(at_command));
2952   p->phone_callflow = CALLFLOW_CALL_DIALING;
2953   p->interface_state = AST_STATE_DIALING;
2954   ast_uri_decode(dstr);
2955   size_t fixdstr = strspn(dstr, AST_DIGIT_ANYDIG);
2956   if (fixdstr == 0) {
2957     ERRORA("dial command failed because of invalid dial number. dial string was: %s\n",
2958            CELLIAX_P_LOG, dstr);
2959     return -1;
2960   }
2961   dstr[fixdstr] = '\0';
2962   sprintf(at_command, "%s%s%s", p->at_dial_pre_number, dstr, p->at_dial_post_number);
2963   res = celliax_serial_write_AT_expect(p, at_command, p->at_dial_expect);
2964   if (res) {
2965     ERRORA("dial command failed, dial string was: %s\n", CELLIAX_P_LOG, at_command);
2966     return -1;
2967   }
2968   // jet - early audio
2969   if (p->at_early_audio) {
2970     ast_queue_control(p->owner, AST_CONTROL_ANSWER);
2971   }
2972 
2973   return 0;
2974 }
2975 
celliax_console_at(int fd,int argc,char * argv[])2976 int celliax_console_at(int fd, int argc, char *argv[])
2977 {
2978   struct celliax_pvt *p = celliax_console_find_desc(celliax_console_active);
2979   char at_cmd[1024];
2980   int i, a, c;
2981 
2982   if (argc == 1)
2983     return RESULT_SHOWUSAGE;
2984   if (!p) {
2985     ast_cli(fd,
2986             "No \"current\" console for celliax_at, please enter 'help celliax_console'\n");
2987     return RESULT_SUCCESS;
2988   }
2989   if (p->controldevprotocol != PROTOCOL_AT) {
2990     ast_cli(fd,
2991             "The \"current\" console is not connected to an 'AT modem' (cellphone)\n");
2992     return RESULT_SUCCESS;
2993   }
2994 
2995   memset(at_cmd, 0, sizeof(at_cmd));
2996   c = 0;
2997   for (i = 1; i < argc; i++) {
2998     for (a = 0; a < strlen(argv[i]); a++) {
2999       at_cmd[c] = argv[i][a];
3000       c++;
3001       if (c == 1022)
3002         break;
3003     }
3004     if (i != argc - 1) {
3005       at_cmd[c] = ' ';
3006       c++;
3007     }
3008     if (c == 1023)
3009       break;
3010   }
3011   celliax_serial_write_AT_noack(p, at_cmd);
3012   return RESULT_SUCCESS;
3013 }
3014 
3015 #ifdef ASTERISK_VERSION_1_2
celliax_manager_sendsms(struct mansession * s,struct message * m)3016 int celliax_manager_sendsms(struct mansession *s, struct message *m)
3017 #endif //ASTERISK_VERSION_1_2
3018 #ifdef ASTERISK_VERSION_1_4
3019 int celliax_manager_sendsms(struct mansession *s, const struct message *m)
3020 #endif //ASTERISK_VERSION_1_4
3021 {
3022   int ret;
3023   char command[512];
3024   const char *interfacename = astman_get_header(m, "Interface");
3025   const char *destinationnumber = astman_get_header(m, "Number");
3026   const char *text = astman_get_header(m, "Text");
3027   const char *action_id = astman_get_header(m, "ActionID");
3028 
3029   if (ast_strlen_zero(interfacename)) {
3030     astman_send_error(s, m, "Interface: missing.\n");
3031     return 0;
3032   }
3033   if (ast_strlen_zero(destinationnumber)) {
3034     astman_send_error(s, m, "Number: missing.\n");
3035     return 0;
3036   }
3037   if (ast_strlen_zero(text)) {
3038     astman_send_error(s, m, "Text: missing.\n");
3039     return 0;
3040   }
3041   if (ast_strlen_zero(action_id)) {
3042     astman_send_error(s, m, "ActionID: missing.\n");
3043     return 0;
3044   }
3045 
3046   memset(command, 0, sizeof(command));
3047 
3048   sprintf(command, "%s/%s|%s|", interfacename, destinationnumber, text);
3049 
3050   ret = celliax_sendsms(NULL, (void *) &command);
3051 
3052 #ifndef ASTERISK_VERSION_1_4
3053   if (!ret) {
3054     ast_cli(s->fd, "Response: Success\r\n");
3055     if (!ast_strlen_zero(action_id))
3056       ast_cli(s->fd, "ActionID: %s\r\n", action_id);
3057     ast_cli(s->fd, "\r\n");
3058     return RESULT_SUCCESS;
3059   } else {
3060     ast_cli(s->fd, "Response: Error\r\n");
3061     if (!ast_strlen_zero(action_id))
3062       ast_cli(s->fd, "ActionID: %s\r\n", action_id);
3063     ast_cli(s->fd, "Message: celliax_manager_sendsms failed\r\n");
3064     ast_cli(s->fd, "\r\n");
3065     return 0;
3066   }
3067 #else /* ASTERISK_VERSION_1_4 */
3068   if (!ret) {
3069     astman_append(s, "Response: Success\r\n");
3070     if (!ast_strlen_zero(action_id))
3071       astman_append(s, "ActionID: %s\r\n", action_id);
3072     astman_append(s, "\r\n");
3073     return RESULT_SUCCESS;
3074   } else {
3075     astman_append(s, "Response: Error\r\n");
3076     if (!ast_strlen_zero(action_id))
3077       astman_append(s, "ActionID: %s\r\n", action_id);
3078     astman_append(s, "Message: celliax_manager_sendsms failed\r\n");
3079     astman_append(s, "\r\n");
3080     return 0;
3081   }
3082 #endif /* ASTERISK_VERSION_1_4 */
3083 
3084   return RESULT_SUCCESS;        //never reached
3085 }
3086 
ucs2_to_utf8(struct celliax_pvt * p,char * ucs2_in,char * utf8_out,size_t outbytesleft)3087 int ucs2_to_utf8(struct celliax_pvt *p, char *ucs2_in, char *utf8_out,
3088                  size_t outbytesleft)
3089 {
3090   char converted[16000];
3091   iconv_t iconv_format;
3092   int iconv_res;
3093   char *outbuf;
3094   char *inbuf;
3095   size_t inbytesleft;
3096   int c;
3097   char stringa[5];
3098   double hexnum;
3099   int i = 0;
3100 
3101   memset(converted, '\0', sizeof(converted));
3102 
3103   DEBUGA_AT("ucs2_in=%s\n", CELLIAX_P_LOG, ucs2_in);
3104   /* cicopet */
3105   for (c = 0; c < strlen(ucs2_in); c++) {
3106     sprintf(stringa, "0x%c%c", ucs2_in[c], ucs2_in[c + 1]);
3107     c++;
3108     hexnum = strtod(stringa, NULL);
3109     converted[i] = hexnum;
3110     i++;
3111   }
3112 
3113   outbuf = utf8_out;
3114   inbuf = converted;
3115 
3116   iconv_format = iconv_open("UTF8", "UCS-2BE");
3117   if (iconv_format == (iconv_t) - 1) {
3118     ERRORA("error: %s\n", CELLIAX_P_LOG, strerror(errno));
3119     return -1;
3120   }
3121 
3122   inbytesleft = i;
3123   iconv_res = iconv(iconv_format, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
3124   if (iconv_res == (size_t) - 1) {
3125     DEBUGA_AT("ciao in=%s, inleft=%d, out=%s, outleft=%d, converted=%s, utf8_out=%s\n",
3126               CELLIAX_P_LOG, inbuf, inbytesleft, outbuf, outbytesleft, converted,
3127               utf8_out);
3128     DEBUGA_AT("error: %s %d\n", CELLIAX_P_LOG, strerror(errno), errno);
3129     return -1;
3130   }
3131   DEBUGA_AT
3132     ("iconv_res=%d,  in=%s, inleft=%d, out=%s, outleft=%d, converted=%s, utf8_out=%s\n",
3133      CELLIAX_P_LOG, iconv_res, inbuf, inbytesleft, outbuf, outbytesleft, converted,
3134      utf8_out);
3135   iconv_close(iconv_format);
3136 
3137   return 0;
3138 }
3139 
utf_to_ucs2(struct celliax_pvt * p,char * utf_in,size_t inbytesleft,char * ucs2_out,size_t outbytesleft)3140 int utf_to_ucs2(struct celliax_pvt *p, char *utf_in, size_t inbytesleft, char *ucs2_out,
3141                 size_t outbytesleft)
3142 {
3143   /* cicopet */
3144   iconv_t iconv_format;
3145   int iconv_res;
3146   char *outbuf;
3147   char *inbuf;
3148   char converted[16000];
3149   int i;
3150   char stringa[16];
3151   char stringa2[16];
3152 
3153   memset(converted, '\0', sizeof(converted));
3154 
3155   outbuf = converted;
3156   inbuf = utf_in;
3157 
3158   iconv_format = iconv_open("UCS-2BE", "UTF8");
3159   if (iconv_format == (iconv_t) - 1) {
3160     ERRORA("error: %s\n", CELLIAX_P_LOG, strerror(errno));
3161     return -1;
3162   }
3163   outbytesleft = 16000;
3164 
3165   DEBUGA_AT("in=%s, inleft=%d, out=%s, outleft=%d, utf_in=%s, converted=%s\n",
3166             CELLIAX_P_LOG, inbuf, inbytesleft, outbuf, outbytesleft, utf_in, converted);
3167   iconv_res = iconv(iconv_format, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
3168   if (iconv_res == (size_t) - 1) {
3169     ERRORA("error: %s %d\n", CELLIAX_P_LOG, strerror(errno), errno);
3170     return -1;
3171   }
3172   DEBUGA_AT
3173     ("iconv_res=%d,  in=%s, inleft=%d, out=%s, outleft=%d, utf_in=%s, converted=%s\n",
3174      CELLIAX_P_LOG, iconv_res, inbuf, inbytesleft, outbuf, outbytesleft, utf_in,
3175      converted);
3176   iconv_close(iconv_format);
3177 
3178   for (i = 0; i < 16000 - outbytesleft; i++) {
3179     memset(stringa, '\0', sizeof(stringa));
3180     memset(stringa2, '\0', sizeof(stringa2));
3181     sprintf(stringa, "%02X", converted[i]);
3182     DEBUGA_AT("character is |%02X|\n", CELLIAX_P_LOG, converted[i]);
3183     stringa2[0] = stringa[strlen(stringa) - 2];
3184     stringa2[1] = stringa[strlen(stringa) - 1];
3185     strncat(ucs2_out, stringa2, ((outbytesleft - strlen(ucs2_out)) - 1));   //add the received line to the buffer
3186     DEBUGA_AT("stringa=%s, stringa2=%s, ucs2_out=%s\n", CELLIAX_P_LOG, stringa, stringa2,
3187               ucs2_out);
3188   }
3189   return 0;
3190 }
3191 
celliax_sendsms(struct ast_channel * c,void * data)3192 int celliax_sendsms(struct ast_channel *c, void *data)
3193 {
3194   char *idest = data;
3195   char rdest[256];
3196   struct celliax_pvt *p = NULL;
3197   char *device;
3198   char *dest;
3199   char *text;
3200   char *stringp = NULL;
3201   int found = 0;
3202   int failed = 0;
3203 
3204   strncpy(rdest, idest, sizeof(rdest) - 1);
3205   ast_log(LOG_DEBUG, "CelliaxSendsms: %s\n", rdest);
3206   ast_log(LOG_DEBUG, "START\n");
3207   /* we can use celliax_request to get the channel, but celliax_request would look for onowned channels, and probably we can send SMSs while a call is ongoing
3208    *
3209    */
3210 
3211   stringp = rdest;
3212   device = strsep(&stringp, "/");
3213   dest = strsep(&stringp, "|");
3214   text = strsep(&stringp, "|");
3215 
3216   if (!device) {
3217     ast_log(LOG_ERROR,
3218             "CelliaxSendsms app do not recognize '%s'. Requires a destination with slashes (interfacename/destinationnumber, TEXT)\n",
3219             idest);
3220     return -1;
3221   }
3222 
3223   if (!dest) {
3224     ast_log(LOG_ERROR,
3225             "CelliaxSendsms app do not recognize '%s'. Requires a destination with slashes (interfacename/destinationnumber, TEXT)\n",
3226             idest);
3227     return -1;
3228   }
3229 
3230   if (!text) {
3231     ast_log(LOG_ERROR,
3232             "CelliaxSendsms app do not recognize '%s'. Requires a destination with slashes (interfacename/destinationnumber, TEXT)\n",
3233             idest);
3234     return -1;
3235   }
3236 
3237   ast_log(LOG_DEBUG, "interfacename:%s, destinationnumber:%s, text:%s\n", device, dest,
3238           text);
3239 
3240   /* lock the interfaces' list */
3241   LOKKA(&celliax_iflock);
3242   /* make a pointer to the first interface in the interfaces list */
3243   p = celliax_iflist;
3244   /* Search for the requested interface and verify if is unowned */
3245   //TODO implement groups a la chan_zap
3246   while (p) {
3247     size_t length = strlen(p->name);
3248     /* is this the requested interface? */
3249     if (strncmp(device, p->name, length) == 0) {
3250       /* this is the requested interface! */
3251       if (option_debug)
3252         DEBUGA_AT("FOUND! interfacename:%s, destinationnumber:%s, text:%s, p->name=%s\n",
3253                   CELLIAX_P_LOG, device, dest, text, p->name);
3254       found = 1;
3255       break;
3256 
3257     }
3258     /* not yet found, next please */
3259     p = p->next;
3260   }
3261   /* unlock the interfaces' list */
3262   UNLOCKA(&celliax_iflock);
3263 
3264   if (!found) {
3265     ast_log(LOG_ERROR, "Interface '%s' requested by CelliaxSendsms NOT FOUND\n", device);
3266     return RESULT_FAILURE;
3267   }
3268 
3269   if (p->controldevprotocol != PROTOCOL_AT) {
3270     ERRORA("CelliaxSendsms supports only AT command cellphones at the moment :-( !\n",
3271            CELLIAX_P_LOG);
3272     return RESULT_FAILURE;
3273   }
3274 
3275   if (p->controldevprotocol == PROTOCOL_AT) {
3276     int err = 0;
3277     char smscommand[16000];
3278     memset(smscommand, '\0', sizeof(smscommand));
3279 
3280     PUSHA_UNLOCKA(&p->controldev_lock);
3281     LOKKA(&p->controldev_lock);
3282 
3283     if (p->no_ucs2) {
3284       sprintf(smscommand, "AT+CMGS=\"%s\"", dest);  //TODO: support phones that only accept pdu mode
3285     } else {
3286       char dest2[1048];
3287 
3288           err = celliax_serial_write_AT_ack(p, "AT+CSCS=\"UCS2\"");
3289           if (err) {
3290             ERRORA
3291               ("AT+CSCS=\"UCS2\" (set TE messages to ucs2)  do not got OK from the phone\n",
3292                CELLIAX_P_LOG);
3293           }
3294 
3295       memset(dest2, '\0', sizeof(dest2));
3296       utf_to_ucs2(p, dest, strlen(dest), dest2, sizeof(dest2));
3297       sprintf(smscommand, "AT+CMGS=\"%s\"", dest2); //TODO: support phones that only accept pdu mode
3298     }
3299     //TODO: support phones that only accept pdu mode
3300     //TODO would be better to lock controldev here
3301     err = celliax_serial_write_AT_noack(p, smscommand);
3302     if (err) {
3303       ERRORA("Error sending SMS\n", CELLIAX_P_LOG);
3304       failed = 1;
3305       goto uscita;
3306     }
3307     err = celliax_serial_AT_expect(p, "> ", 0, 1);  // wait 1.5s for the prompt, no  crlf
3308 #if 1
3309     if (err) {
3310       DEBUGA_AT
3311         ("Error or timeout getting prompt '> ' for sending sms directly to the remote party. BTW, seems that we cannot do that with Motorola c350, so we'll write to cellphone memory, then send from memory\n",
3312          CELLIAX_P_LOG);
3313 
3314       err = celliax_serial_write_AT_ack(p, "ATE1"); //motorola (at least c350) do not echo the '>' prompt when in ATE0... go figure!!!!
3315       if (err) {
3316         ERRORA("Error activating echo from modem\n", CELLIAX_P_LOG);
3317       }
3318       p->at_cmgw[0] = '\0';
3319       sprintf(smscommand, "AT+CMGW=\"%s\"", dest);  //TODO: support phones that only accept pdu mode
3320       err = celliax_serial_write_AT_noack(p, smscommand);
3321       if (err) {
3322         ERRORA("Error writing SMS destination to the cellphone memory\n", CELLIAX_P_LOG);
3323         failed = 1;
3324         goto uscita;
3325       }
3326       err = celliax_serial_AT_expect(p, "> ", 0, 1);    // wait 1.5s for the prompt, no  crlf
3327       if (err) {
3328         ERRORA
3329           ("Error or timeout getting prompt '> ' for writing sms text in cellphone memory\n",
3330            CELLIAX_P_LOG);
3331         failed = 1;
3332         goto uscita;
3333       }
3334     }
3335 #endif
3336 
3337     //sprintf(text,"ciao 123 belè новости לק ראת ﺎﻠﺠﻤﻋﺓ 人大"); //let's test the beauty of utf
3338     memset(smscommand, '\0', sizeof(smscommand));
3339     if (p->no_ucs2) {
3340       sprintf(smscommand, "%s", text);
3341     } else {
3342       utf_to_ucs2(p, text, strlen(text), smscommand, sizeof(smscommand));
3343     }
3344 
3345     smscommand[strlen(smscommand)] = 0x1A;
3346     DEBUGA_AT("smscommand len is: %d, text is:|||%s|||\n", CELLIAX_P_LOG,
3347               strlen(smscommand), smscommand);
3348 
3349     err = celliax_serial_write_AT_ack_nocr_longtime(p, smscommand);
3350     //TODO would be better to unlock controldev here
3351     if (err) {
3352       ERRORA("Error writing SMS text to the cellphone memory\n", CELLIAX_P_LOG);
3353       //return RESULT_FAILURE;
3354       failed = 1;
3355       goto uscita;
3356     }
3357     if (p->at_cmgw[0]) {
3358       sprintf(smscommand, "AT+CMSS=%s", p->at_cmgw);
3359       err = celliax_serial_write_AT_expect_longtime(p, smscommand, "OK");
3360       if (err) {
3361         ERRORA("Error sending SMS from the cellphone memory\n", CELLIAX_P_LOG);
3362         //return RESULT_FAILURE;
3363         failed = 1;
3364         goto uscita;
3365       }
3366 
3367       err = celliax_serial_write_AT_ack(p, "ATE0"); //motorola (at least c350) do not echo the '>' prompt when in ATE0... go figure!!!!
3368       if (err) {
3369         ERRORA("Error de-activating echo from modem\n", CELLIAX_P_LOG);
3370       }
3371     }
3372   uscita:
3373     usleep(1000);
3374 
3375     if (p->at_cmgw[0]) {
3376 
3377       /* let's see what we've sent, just for check TODO: Motorola it's not reliable! Motorola c350 tells that all was sent, but is not true! It just sends how much it fits into one SMS FIXME: need an algorithm to calculate how many ucs2 chars fits into an SMS. It make difference based, probably, on the GSM alphabet translation, or so */
3378       sprintf(smscommand, "AT+CMGR=%s", p->at_cmgw);
3379       err = celliax_serial_write_AT_ack(p, smscommand);
3380       if (err) {
3381         ERRORA("Error reading SMS back from the cellphone memory\n", CELLIAX_P_LOG);
3382       }
3383 
3384       /* let's delete from cellphone memory what we've sent */
3385       sprintf(smscommand, "AT+CMGD=%s", p->at_cmgw);
3386       err = celliax_serial_write_AT_ack(p, smscommand);
3387       if (err) {
3388         ERRORA("Error deleting SMS from the cellphone memory\n", CELLIAX_P_LOG);
3389       }
3390 
3391       p->at_cmgw[0] = '\0';
3392     }
3393     //usleep(500000);             //.5 secs
3394     UNLOCKA(&p->controldev_lock);
3395     POPPA_UNLOCKA(&p->controldev_lock);
3396   }
3397 
3398   ast_log(LOG_DEBUG, "FINISH\n");
3399   if (failed)
3400     return -1;
3401   else
3402     return RESULT_SUCCESS;
3403 }
3404 
3405 #ifdef CELLIAX_DIR
3406 /* For simplicity, I'm keeping the format compatible with the voicemail config,
3407    but i'm open to suggestions for isolating it */
3408 #define CELLIAX_DIR_CONFIG "directoriax.conf"
3409 
3410 /* How many digits to read in */
3411 #define CELLIAX_DIR_NUMDIGITS 3
3412 
celliax_dir_realtime(char * context)3413 struct ast_config *celliax_dir_realtime(char *context)
3414 {
3415   //TODO: all the realtime stuff has to be re-made
3416   struct ast_config *cfg;
3417   struct celliax_pvt *p = NULL;
3418 #ifdef ASTERISK_VERSION_1_6_0
3419   struct ast_flags config_flags = { 0 };
3420 #endif /* ASTERISK_VERSION_1_6_0 */
3421 
3422   /* Load flat file config. */
3423 #ifdef ASTERISK_VERSION_1_6_0
3424   cfg = ast_config_load(CELLIAX_DIR_CONFIG, config_flags);
3425 #else
3426   cfg = ast_config_load(CELLIAX_DIR_CONFIG);
3427 #endif /* ASTERISK_VERSION_1_6_0 */
3428 
3429   if (!cfg) {
3430     /* Loading config failed. */
3431     WARNINGA
3432       ("Loading directoriax.conf config file failed. It's not necessary, continuing.\n",
3433        CELLIAX_P_LOG);
3434     return NULL;
3435   }
3436   return cfg;
3437 }
3438 
celliax_dir_convert(char * lastname)3439 static char *celliax_dir_convert(char *lastname)
3440 {
3441   char *tmp;
3442   int lcount = 0;
3443   tmp = malloc(CELLIAX_DIR_NUMDIGITS + 1);
3444   if (tmp) {
3445     while ((*lastname > 32) && lcount < CELLIAX_DIR_NUMDIGITS) {
3446       switch (toupper(*lastname)) {
3447       case '1':
3448         tmp[lcount++] = '1';
3449         break;
3450       case '2':
3451       case 'A':
3452       case 'B':
3453       case 'C':
3454         tmp[lcount++] = '2';
3455         break;
3456       case '3':
3457       case 'D':
3458       case 'E':
3459       case 'F':
3460         tmp[lcount++] = '3';
3461         break;
3462       case '4':
3463       case 'G':
3464       case 'H':
3465       case 'I':
3466         tmp[lcount++] = '4';
3467         break;
3468       case '5':
3469       case 'J':
3470       case 'K':
3471       case 'L':
3472         tmp[lcount++] = '5';
3473         break;
3474       case '6':
3475       case 'M':
3476       case 'N':
3477       case 'O':
3478         tmp[lcount++] = '6';
3479         break;
3480       case '7':
3481       case 'P':
3482       case 'Q':
3483       case 'R':
3484       case 'S':
3485         tmp[lcount++] = '7';
3486         break;
3487       case '8':
3488       case 'T':
3489       case 'U':
3490       case 'V':
3491         tmp[lcount++] = '8';
3492         break;
3493       case '9':
3494       case 'W':
3495       case 'X':
3496       case 'Y':
3497       case 'Z':
3498         tmp[lcount++] = '9';
3499         break;
3500       }
3501       lastname++;
3502     }
3503     tmp[lcount] = '\0';
3504   }
3505   return tmp;
3506 }
3507 
celliax_console_celliax_dir_export(int fd,int argc,char * argv[])3508 int celliax_console_celliax_dir_export(int fd, int argc, char *argv[])
3509 {
3510   struct ast_config *cfg;
3511 
3512   struct ast_variable *v;
3513   char *start, *pos, *stringp, *space, *options = NULL, *conv = NULL;
3514   struct celliax_pvt *p = celliax_console_find_desc(celliax_console_active);
3515   char *context = "default";
3516   char *s;
3517   char *var, *value;
3518   int fromcell = 0;
3519   int fromskype = 0;
3520   char name[256] = "";
3521   char phonebook_direct_calling_ext[7] = "";
3522   char write_entry_command[256] = "";
3523   char entry_number[256] = "";
3524   char entry_text[256] = "";
3525   char final_entry_text[256] = "";
3526   int res;
3527   int tocell = 0;
3528 #ifdef CELLIAX_LIBCSV
3529   int tocsv = 0;
3530   int tovcf = 0;
3531 #endif /* CELLIAX_LIBCSV */
3532 
3533   if (argc < 3 || argc > 4)
3534     return RESULT_SHOWUSAGE;
3535   if (!p) {
3536     ast_cli(fd, "No \"current\" console ???, please enter 'help celliax_console'\n");
3537     return RESULT_SUCCESS;
3538   }
3539 
3540   if (!strcasecmp(argv[1], "tocell"))
3541     tocell = 1;
3542 #ifdef CELLIAX_LIBCSV
3543   else if (!strcasecmp(argv[1], "tocsv"))
3544     tocsv = 1;
3545   else if (!strcasecmp(argv[1], "tovcf"))
3546     tovcf = 1;
3547 #endif /* CELLIAX_LIBCSV */
3548   else {
3549     ast_cli(fd,
3550 #ifdef CELLIAX_LIBCSV
3551             "\n\nYou have neither specified 'tocell' nor 'tocsv'\n\n");
3552 #else /* CELLIAX_LIBCSV */
3553             "\n\nYou have not specified 'tocell'\n\n");
3554 #endif /* CELLIAX_LIBCSV */
3555     return RESULT_SHOWUSAGE;
3556   }
3557   if (tocell)
3558     if (p->controldevprotocol != PROTOCOL_AT) {
3559       ast_cli(fd,
3560               "Exporting to the cellphone phonebook is currently supported only on \"AT\" cellphones :( !\n");
3561       return RESULT_SUCCESS;
3562     }
3563 #ifdef CELLIAX_LIBCSV
3564   if (tocsv || tovcf)
3565     if (argc != 4) {
3566       ast_cli(fd, "\n\nYou have to specify a filename with 'tocsv'\n\n");
3567       return RESULT_SHOWUSAGE;
3568     }
3569 #endif /* CELLIAX_LIBCSV */
3570 
3571   if (option_debug)
3572     NOTICA("celliax_cellphonenumber is: %s\n", CELLIAX_P_LOG, argv[2]);
3573 
3574 #ifdef CELLIAX_LIBCSV
3575   if (tocsv) {
3576     if (option_debug)
3577       NOTICA("filename is: %s\n", CELLIAX_P_LOG, argv[3]);
3578     //ast_cli(fd, "\n\nnot yet implemented :P \n");
3579     //return RESULT_SUCCESS;
3580   }
3581   if (tovcf) {
3582     if (option_debug)
3583       NOTICA("filename is: %s\n", CELLIAX_P_LOG, argv[3]);
3584     ast_cli(fd, "\n\nnot yet implemented :P \n");
3585     return RESULT_SUCCESS;
3586   }
3587 #endif /* CELLIAX_LIBCSV */
3588 
3589   cfg = celliax_dir_realtime(context);
3590   if (!cfg) {
3591     return -1;
3592   }
3593 
3594   if (tocell) {
3595     /* which phonebook to use, use the SIM  */
3596     res = celliax_serial_write_AT_ack(p, "AT+CPBS=SM");
3597     if (res) {
3598       WARNINGA("AT+CPBS=SM failed, continue\n", CELLIAX_P_LOG);
3599     }
3600     /* which phonebook to use, trying to use phone, not SIM  */
3601     res = celliax_serial_write_AT_ack(p, "AT+CPBS=ME");
3602     if (res) {
3603       WARNINGA("AT+CPBS=ME failed, continue\n", CELLIAX_P_LOG);
3604     }
3605     /* retrieve the fields lenght in the selected phonebook  */
3606     p->phonebook_querying = 1;
3607     res = celliax_serial_write_AT_ack(p, "AT+CPBR=?");
3608     if (res) {
3609       WARNINGA("AT+CPBR=? failed, continue\n", CELLIAX_P_LOG);
3610     }
3611     p->phonebook_querying = 0;
3612 
3613     v = ast_variable_browse(cfg, context);
3614     /* Find all candidate extensions */
3615     while (v) {
3616       /* Find a candidate extension */
3617       start = strdup(v->value);
3618       if (strcasestr(start, "fromcell=yes")) {
3619         fromcell = 1;
3620         fromskype = 0;
3621 
3622       }
3623       if (strcasestr(start, "fromskype=yes")) {
3624         fromcell = 0;
3625         fromskype = 1;
3626 
3627       }
3628 
3629       if (start && !strcasestr(start, "hidefromdir=yes")) {
3630         memset(name, 0, sizeof(name));
3631         memset(phonebook_direct_calling_ext, 0, sizeof(phonebook_direct_calling_ext));
3632         memset(write_entry_command, 0, sizeof(write_entry_command));
3633         memset(entry_number, 0, sizeof(entry_number));
3634         memset(entry_text, 0, sizeof(entry_text));
3635         memset(final_entry_text, 0, sizeof(final_entry_text));
3636 
3637         DEBUGA_AT("v->name=%s\n", CELLIAX_P_LOG, v->name);
3638         DEBUGA_AT("v->value=%s\n", CELLIAX_P_LOG, v->value);
3639 
3640         stringp = start;
3641         strsep(&stringp, ",");
3642         pos = strsep(&stringp, ",");
3643         if (pos) {
3644           ast_copy_string(name, pos, sizeof(name));
3645           if (strchr(pos, ' ')) {
3646             space = strchr(pos, ' ');
3647             *space = '\0';
3648           }
3649           if (pos) {
3650             conv = celliax_dir_convert(pos);
3651             DEBUGA_AT("<pos=>%s<conv=>%s<\n", CELLIAX_P_LOG, pos, conv);
3652 
3653             options = strdup(v->value);
3654             strsep(&options, ",");
3655             strsep(&options, ",");
3656             strsep(&options, ",");
3657             strsep(&options, ",");
3658             DEBUGA_AT("options=%s\n", CELLIAX_P_LOG, options);
3659 
3660             while ((s = strsep(&options, "|"))) {
3661               value = s;
3662               if ((var = strsep(&value, "=")) && value) {
3663                 DEBUGA_AT("var=%s value=%s\n", CELLIAX_P_LOG, var, value);
3664                 if (!strcmp(var, "phonebook_direct_calling_ext"))
3665                   strncpy(phonebook_direct_calling_ext, value, 6);
3666               }
3667             }
3668 
3669             res =
3670               snprintf(entry_number, p->phonebook_number_lenght + 1, "%s%s%d%s%s",
3671                        argv[2], "p", p->celliax_dir_prefix, "p",
3672                        phonebook_direct_calling_ext);
3673             if (res == (p->phonebook_number_lenght + 1)
3674                 || res > (p->phonebook_number_lenght + 1)) {
3675               ERRORA("entry_number truncated, was: '%s%s%d%s%s', now is: '%s'\n",
3676                      CELLIAX_P_LOG, argv[2], "p", p->celliax_dir_prefix, "p",
3677                      phonebook_direct_calling_ext, entry_number);
3678               //FIXME: abort ???
3679 
3680             }
3681 
3682             res = snprintf(final_entry_text, p->phonebook_text_lenght + 1, "%s", name); //FIXME result not checked
3683 
3684             res =
3685               snprintf(write_entry_command, sizeof(write_entry_command) - 1,
3686                        "AT+CPBW=,\"%s\",,\"%s\"", entry_number, final_entry_text);
3687             if (res == (sizeof(write_entry_command) - 1)
3688                 || res > (sizeof(write_entry_command) - 1)) {
3689               WARNINGA
3690                 ("write_entry_command truncated, was supposed: 'AT+CPBW=,\"%s\",,\"%s\"', now is: '%s'\n",
3691                  CELLIAX_P_LOG, entry_number, final_entry_text, write_entry_command);
3692             }
3693             //if (option_debug)
3694             NOTICA("%s\n", CELLIAX_P_LOG, write_entry_command);
3695           }
3696         }
3697         if (conv)
3698           free(conv);
3699         if (start)
3700           free(start);
3701         if (options)
3702           free(options);
3703       }
3704       v = v->next;
3705     }
3706   }
3707 #ifdef CELLIAX_LIBCSV
3708   if (tocsv) {
3709 
3710     v = ast_variable_browse(cfg, context);
3711     /* Find all candidate extensions */
3712     while (v) {
3713       /* Find a candidate extension */
3714       start = strdup(v->value);
3715       if (strcasestr(start, "fromcell=yes")) {
3716         fromcell = 1;
3717         fromskype = 0;
3718 
3719       }
3720       if (strcasestr(start, "fromskype=yes")) {
3721         fromcell = 0;
3722         fromskype = 1;
3723 
3724       }
3725 
3726       if (start && !strcasestr(start, "hidefromdir=yes")) {
3727         memset(name, 0, sizeof(name));
3728         memset(phonebook_direct_calling_ext, 0, sizeof(phonebook_direct_calling_ext));
3729         memset(write_entry_command, 0, sizeof(write_entry_command));
3730         memset(entry_number, 0, sizeof(entry_number));
3731         memset(entry_text, 0, sizeof(entry_text));
3732         memset(final_entry_text, 0, sizeof(final_entry_text));
3733 
3734         DEBUGA_AT("v->name=%s\n", CELLIAX_P_LOG, v->name);
3735         DEBUGA_AT("v->value=%s\n", CELLIAX_P_LOG, v->value);
3736 
3737         stringp = start;
3738         strsep(&stringp, ",");
3739         pos = strsep(&stringp, ",");
3740         if (pos) {
3741           ast_copy_string(name, pos, sizeof(name));
3742           if (strchr(pos, ' ')) {
3743             space = strchr(pos, ' ');
3744             *space = '\0';
3745           }
3746           if (pos) {
3747             conv = celliax_dir_convert(pos);
3748             DEBUGA_AT("<pos=>%s<conv=>%s<\n", CELLIAX_P_LOG, pos, conv);
3749 
3750             options = strdup(v->value);
3751             strsep(&options, ",");
3752             strsep(&options, ",");
3753             strsep(&options, ",");
3754             strsep(&options, ",");
3755             DEBUGA_AT("options=%s\n", CELLIAX_P_LOG, options);
3756 
3757             while ((s = strsep(&options, "|"))) {
3758               value = s;
3759               if ((var = strsep(&value, "=")) && value) {
3760                 DEBUGA_AT("var=%s value=%s\n", CELLIAX_P_LOG, var, value);
3761                 if (!strcmp(var, "phonebook_direct_calling_ext"))
3762                   strncpy(phonebook_direct_calling_ext, value, 6);
3763               }
3764             }
3765 
3766             //FIXME choose a logic for fields maximum lenght
3767             res =
3768               snprintf(entry_number, sizeof(entry_number) - 1, "%s%s%d%s%s", argv[2], "p",
3769                        p->celliax_dir_prefix, "p", phonebook_direct_calling_ext);
3770             if (res == (sizeof(entry_number) - 1)
3771                 || res > (sizeof(entry_number) - 1)) {
3772               ERRORA("entry_number truncated, was: '%s%s%d%s%s', now is: '%s'\n",
3773                      CELLIAX_P_LOG, argv[2], "p", p->celliax_dir_prefix, "p",
3774                      phonebook_direct_calling_ext, entry_number);
3775               //FIXME: abort ???
3776 
3777             }
3778 
3779             res = snprintf(final_entry_text, sizeof(final_entry_text) - 1, "%s", name); //FIXME result not checked
3780 
3781             int i, a;
3782 
3783             a = 0;
3784             for (i = 0; i < p->csv_complete_name_pos - 1; i++) {
3785               if (p->csv_separator_is_semicolon)
3786                 write_entry_command[a] = ';';
3787               else
3788                 write_entry_command[a] = ',';
3789               a++;
3790             }
3791             //NOTICA("i=%d a=%d\n", CELLIAX_P_LOG, i, a);
3792 
3793             write_entry_command[a] = '"';
3794             a++;
3795             //NOTICA("i=%d a=%d\n", CELLIAX_P_LOG, i, a);
3796             for (i = 0; i < strlen(final_entry_text); i++) {
3797               write_entry_command[a] = final_entry_text[i];
3798               a++;
3799             }
3800             //NOTICA("i=%d a=%d\n", CELLIAX_P_LOG, i, a);
3801             write_entry_command[a] = '"';
3802             a++;
3803             //NOTICA("i=%d a=%d\n", CELLIAX_P_LOG, i, a);
3804             for (i = 0; i < (p->csv_business_phone_pos - p->csv_complete_name_pos); i++) {
3805               if (p->csv_separator_is_semicolon)
3806                 write_entry_command[a] = ';';
3807               else
3808                 write_entry_command[a] = ',';
3809               a++;
3810             }
3811 
3812             //NOTICA("i=%d a=%d\n", CELLIAX_P_LOG, i, a);
3813 
3814             write_entry_command[a] = '"';
3815             a++;
3816             //NOTICA("i=%d a=%d\n", CELLIAX_P_LOG, i, a);
3817             for (i = 0; i < strlen(entry_number); i++) {
3818               write_entry_command[a] = entry_number[i];
3819               a++;
3820             }
3821             //NOTICA("i=%d a=%d\n", CELLIAX_P_LOG, i, a);
3822             write_entry_command[a] = '"';
3823             a++;
3824             //NOTICA("i=%d a=%d\n", CELLIAX_P_LOG, i, a);
3825 
3826             if (option_debug)
3827               NOTICA("%s\n", CELLIAX_P_LOG, write_entry_command);
3828           }
3829         }
3830         if (conv)
3831           free(conv);
3832         if (start)
3833           free(start);
3834         if (options)
3835           free(options);
3836       }
3837       v = v->next;
3838     }
3839 
3840   }
3841   if (tovcf) {
3842 //TODO implementation here
3843   }
3844 #endif /*  CELLIAX_LIBCSV */
3845   ast_config_destroy(cfg);
3846   return 0;
3847 }
3848 
3849 #ifdef CELLIAX_LIBCSV
3850 
celliax_cb1(char * s,size_t len,void * data)3851 void celliax_cb1(char *s, size_t len, void *data)
3852 {
3853   struct celliax_pvt *p = data;
3854   char field_content[256];
3855 
3856   p->csv_fields++;
3857   memset(field_content, 0, sizeof(field_content));
3858   strncpy(field_content, s,
3859           sizeof(field_content) > (len + 1) ? len : (sizeof(field_content) - 1));
3860   if (p->csv_fields == p->csv_complete_name_pos) {
3861     strncpy(p->csv_complete_name, field_content, sizeof(p->csv_complete_name) - 1);
3862   }
3863   if (p->csv_fields == p->csv_email_pos) {
3864     strncpy(p->csv_email, field_content, sizeof(p->csv_email) - 1);
3865   }
3866   if (p->csv_fields == p->csv_home_phone_pos) {
3867     strncpy(p->csv_home_phone, field_content, sizeof(p->csv_home_phone) - 1);
3868   }
3869   if (p->csv_fields == p->csv_mobile_phone_pos) {
3870     strncpy(p->csv_mobile_phone, field_content, sizeof(p->csv_mobile_phone) - 1);
3871   }
3872   if (p->csv_fields == p->csv_business_phone_pos) {
3873     strncpy(p->csv_business_phone, field_content, sizeof(p->csv_business_phone) - 1);
3874   }
3875 }
3876 
celliax_cb2(char c,void * data)3877 void celliax_cb2(char c, void *data)
3878 {
3879   struct celliax_pvt *p = data;
3880 
3881   p->csv_rows++;
3882   p->csv_fields = 0;
3883 
3884   if (p->csv_first_row_is_title && p->csv_rows == 1) {
3885     //do nothing
3886   } else {
3887     if (strlen(p->csv_complete_name)) {
3888       if (option_debug)
3889         NOTICA
3890           ("ROW %d ENDED, complete_name=%s, email=%s, home_phone=%s, mobile_phone=%s, business_phone=%s\n",
3891            CELLIAX_P_LOG, p->csv_rows,
3892            strlen(p->csv_complete_name) ? p->csv_complete_name : "N/A",
3893            strlen(p->csv_email) ? p->csv_email : "N/A",
3894            strlen(p->csv_home_phone) ? p->csv_home_phone : "N/A",
3895            strlen(p->csv_mobile_phone) ? p->csv_mobile_phone : "N/A",
3896            strlen(p->csv_business_phone) ? p->csv_business_phone : "N/A");
3897     }
3898 
3899     /* write entries in phonebook file */
3900     if (p->phonebook_writing_fp) {
3901       celliax_dir_entry_extension++;
3902 
3903       if (strlen(p->csv_complete_name)) {
3904         /* let's start with home_phone */
3905         if (strlen(p->csv_home_phone)) {
3906           fprintf(p->phonebook_writing_fp,
3907                   "%s  => ,%s %sSKO,,,hidefromdir=%s|phonebook_direct_calling_ext=%d%s%.4d|phonebook_entry_fromcsv=%s|phonebook_entry_owner=%s\n",
3908                   p->csv_home_phone, p->csv_complete_name, "HOME", "no",
3909                   p->celliax_dir_entry_extension_prefix, "2", celliax_dir_entry_extension,
3910                   "yes", "not_specified");
3911           fprintf(p->phonebook_writing_fp,
3912                   "%s  => ,%s %sDO,,,hidefromdir=%s|phonebook_direct_calling_ext=%d%s%.4d|phonebook_entry_fromcsv=%s|phonebook_entry_owner=%s\n",
3913                   p->csv_home_phone, p->csv_complete_name, "HOME", "no",
3914                   p->celliax_dir_entry_extension_prefix, "3", celliax_dir_entry_extension,
3915                   "yes", "not_specified");
3916         }
3917 
3918         /* now business_phone */
3919         if (strlen(p->csv_business_phone)) {
3920           fprintf(p->phonebook_writing_fp,
3921                   "%s  => ,%s %sSKO,,,hidefromdir=%s|phonebook_direct_calling_ext=%d%s%.4d|phonebook_entry_fromcsv=%s|phonebook_entry_owner=%s\n",
3922                   p->csv_business_phone, p->csv_complete_name, "BIZ", "no",
3923                   p->celliax_dir_entry_extension_prefix, "2", celliax_dir_entry_extension,
3924                   "yes", "not_specified");
3925           fprintf(p->phonebook_writing_fp,
3926                   "%s  => ,%s %sDO,,,hidefromdir=%s|phonebook_direct_calling_ext=%d%s%.4d|phonebook_entry_fromcsv=%s|phonebook_entry_owner=%s\n",
3927                   p->csv_business_phone, p->csv_complete_name, "BIZ", "no",
3928                   p->celliax_dir_entry_extension_prefix, "3", celliax_dir_entry_extension,
3929                   "yes", "not_specified");
3930         }
3931 
3932         /* let's end with mobile_phone */
3933         if (strlen(p->csv_mobile_phone)) {
3934           fprintf(p->phonebook_writing_fp,
3935                   "%s  => ,%s %sSKO,,,hidefromdir=%s|phonebook_direct_calling_ext=%d%s%.4d|phonebook_entry_fromcsv=%s|phonebook_entry_owner=%s\n",
3936                   p->csv_mobile_phone, p->csv_complete_name, "CELL", "no",
3937                   p->celliax_dir_entry_extension_prefix, "2", celliax_dir_entry_extension,
3938                   "yes", "not_specified");
3939           fprintf(p->phonebook_writing_fp,
3940                   "%s  => ,%s %sDO,,,hidefromdir=%s|phonebook_direct_calling_ext=%d%s%.4d|phonebook_entry_fromcsv=%s|phonebook_entry_owner=%s\n",
3941                   p->csv_mobile_phone, p->csv_complete_name, "CELL", "no",
3942                   p->celliax_dir_entry_extension_prefix, "3", celliax_dir_entry_extension,
3943                   "yes", "not_specified");
3944         }
3945       }
3946 
3947     }
3948 
3949   }
3950 }
3951 
3952 #endif /* CELLIAX_LIBCSV */
3953 
celliax_console_celliax_dir_import(int fd,int argc,char * argv[])3954 int celliax_console_celliax_dir_import(int fd, int argc, char *argv[])
3955 {
3956   int res;
3957   struct celliax_pvt *p = celliax_console_find_desc(celliax_console_active);
3958   char list_command[64];
3959   char fn[256];
3960   char date[256] = "";
3961   time_t t;
3962   char *configfile = CELLIAX_DIR_CONFIG;
3963   int add_to_celliax_dir_conf = 1;
3964   //int fromskype = 0;
3965   int fromcell = 0;
3966 #ifdef CELLIAX_LIBCSV
3967   int fromcsv = 0;
3968   int fromvcf = 0;
3969 #endif /* CELLIAX_LIBCSV */
3970 
3971   if (argc < 3 || argc > 4)
3972     return RESULT_SHOWUSAGE;
3973   if (!p) {
3974     ast_cli(fd, "No \"current\" console ???, please enter 'help celliax_console'\n");
3975     return RESULT_SUCCESS;
3976   }
3977 
3978   if (!strcasecmp(argv[1], "add"))
3979     add_to_celliax_dir_conf = 1;
3980   else if (!strcasecmp(argv[1], "replace"))
3981     add_to_celliax_dir_conf = 0;
3982   else {
3983     ast_cli(fd, "\n\nYou have neither specified 'add' nor 'replace'\n\n");
3984     return RESULT_SHOWUSAGE;
3985   }
3986 
3987   //if (!strcasecmp(argv[2], "fromskype"))
3988   //fromskype = 1;
3989   //else
3990 
3991   if (!strcasecmp(argv[2], "fromcell"))
3992     fromcell = 1;
3993 #ifdef CELLIAX_LIBCSV
3994   else if (!strcasecmp(argv[2], "fromcsv"))
3995     fromcsv = 1;
3996   else if (!strcasecmp(argv[2], "fromvcf"))
3997     fromvcf = 1;
3998 #endif /* CELLIAX_LIBCSV */
3999   else {
4000     ast_cli(fd, "\n\nYou have neither specified 'fromcell' neither 'fromcsv'\n\n");
4001     return RESULT_SHOWUSAGE;
4002   }
4003 
4004 #ifdef CELLIAX_LIBCSV
4005   if (fromcsv || fromvcf)
4006     if (argc != 4) {
4007       ast_cli(fd,
4008               "\n\nYou have to specify a filename with 'fromcsv' or with 'fromvcf'\n\n");
4009       return RESULT_SHOWUSAGE;
4010     }
4011 #endif /* CELLIAX_LIBCSV */
4012   if (fromcell)
4013     if (p->controldevprotocol != PROTOCOL_AT) {
4014       ast_cli(fd,
4015               "Importing from cellphone is currently supported only on \"AT\" cellphones :( !\n");
4016       //fclose(p->phonebook_writing_fp);
4017       //celliax_dir_create_extensions();
4018       return RESULT_SUCCESS;
4019     }
4020 
4021   if (fromcell)
4022     if (argc != 3) {
4023       ast_cli(fd, "\n\nYou don't have to specify a filename with 'fromcell'\n\n");
4024       return RESULT_SHOWUSAGE;
4025     }
4026 #ifdef CELLIAX_LIBCSV
4027   if (fromvcf) {
4028     if (option_debug)
4029       NOTICA("filename is: %s\n", CELLIAX_P_LOG, argv[3]);
4030     ast_cli(fd, "\n\nnot yet implemented :P \n");
4031     return RESULT_SUCCESS;
4032   }
4033 #endif /* CELLIAX_LIBCSV */
4034 
4035   /*******************************************************************************************/
4036 
4037   if (configfile[0] == '/') {
4038     ast_copy_string(fn, configfile, sizeof(fn));
4039   } else {
4040     snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
4041   }
4042   if (option_debug)
4043     NOTICA("Opening '%s'\n", CELLIAX_P_LOG, fn);
4044   time(&t);
4045   ast_copy_string(date, ctime(&t), sizeof(date));
4046 
4047   if (add_to_celliax_dir_conf)
4048     p->phonebook_writing_fp = fopen(fn, "a+");
4049   else
4050     p->phonebook_writing_fp = fopen(fn, "w+");
4051 
4052   if (p->phonebook_writing_fp) {
4053     if (add_to_celliax_dir_conf) {
4054       if (option_debug)
4055         NOTICA("Opened '%s' for appending \n", CELLIAX_P_LOG, fn);
4056       fprintf(p->phonebook_writing_fp, ";!\n");
4057       fprintf(p->phonebook_writing_fp, ";! Update Date: %s", date);
4058       fprintf(p->phonebook_writing_fp, ";! Updated by: %s, %d\n", __FILE__, __LINE__);
4059       fprintf(p->phonebook_writing_fp, ";!\n");
4060     } else {
4061       if (option_debug)
4062         NOTICA("Opened '%s' for writing \n", CELLIAX_P_LOG, fn);
4063       fprintf(p->phonebook_writing_fp, ";!\n");
4064       fprintf(p->phonebook_writing_fp, ";! Automatically generated configuration file\n");
4065       fprintf(p->phonebook_writing_fp, ";! Filename: %s (%s)\n", configfile, fn);
4066       fprintf(p->phonebook_writing_fp, ";! Creation Date: %s", date);
4067       fprintf(p->phonebook_writing_fp, ";! Generated by: %s, %d\n", __FILE__, __LINE__);
4068       fprintf(p->phonebook_writing_fp, ";!\n");
4069       fprintf(p->phonebook_writing_fp, "[general]\n\n");
4070       fprintf(p->phonebook_writing_fp, "[default]\n");
4071     }
4072 
4073 #ifdef CELLIAX_LIBCSV
4074     //FIXME: if add_to_celliax_dir_conf parse the "old" config file, so to have the correct next entry id-exten
4075     if (fromcsv) {
4076       if (option_debug)
4077         NOTICA("filename is: %s\n", CELLIAX_P_LOG, argv[3]);
4078 
4079 /************************/
4080       FILE *fp;
4081       struct csv_parser *csvp;
4082       char buf[1024];
4083       size_t bytes_read;
4084       unsigned char options = 0;
4085 
4086       p->csv_rows = 0;
4087       p->csv_fields = 0;
4088 
4089       if (p->csv_separator_is_semicolon) {
4090         if (csv_init(&csvp, options | CSV_USE_SEMICOLON_SEPARATOR) != 0) {
4091           ERRORA("Failed to initialize csv parser\n", CELLIAX_P_LOG);
4092           return RESULT_SUCCESS;
4093         }
4094       } else {
4095         if (csv_init(&csvp, options) != 0) {
4096           ERRORA("Failed to initialize csv parser\n", CELLIAX_P_LOG);
4097           return RESULT_SUCCESS;
4098         }
4099 
4100       }
4101 
4102       fp = fopen(argv[3], "rb");
4103       if (!fp) {
4104         ERRORA("Failed to open %s: %s\n", CELLIAX_P_LOG, argv[3], strerror(errno));
4105         return RESULT_SUCCESS;
4106       }
4107       while ((bytes_read = fread(buf, 1, 1024, fp)) > 0) {
4108         if (csv_parse(csvp, buf, bytes_read, celliax_cb1, celliax_cb2, p) != bytes_read) {
4109           ERRORA("Error while parsing file: %s\n", CELLIAX_P_LOG,
4110                  csv_strerror(csv_error(csvp)));
4111         }
4112       }
4113 
4114       csv_fini(csvp, celliax_cb1, celliax_cb2, p);
4115 
4116       if (ferror(fp)) {
4117         ERRORA("Error while reading file %s\n", CELLIAX_P_LOG, argv[3]);
4118         fclose(fp);
4119         return RESULT_SUCCESS;
4120       }
4121 
4122       fclose(fp);
4123       if (option_debug)
4124         NOTICA("%s: %d fields, %d rows\n", CELLIAX_P_LOG, argv[3], p->csv_fields,
4125                p->csv_rows);
4126 
4127       csv_free(csvp);
4128 
4129     /**************************/
4130     }
4131 #endif /* CELLIAX_LIBCSV */
4132 
4133   /*******************************************************************************************/
4134     //if (fromskype) {
4135     //ast_cli(fd,
4136     //"Skype not supported in celliax_dir. Load chan_skypiax and use skypiax_dir!\n");
4137     //}
4138 
4139   /*******************************************************************************************/
4140     if (fromcell) {
4141       /* which phonebook to use, use the SIM  */
4142       res = celliax_serial_write_AT_ack(p, "AT+CPBS=SM");
4143       if (res) {
4144         WARNINGA("AT+CPBS=SM failed, continue\n", CELLIAX_P_LOG);
4145       }
4146       /* which phonebook to use, trying to use combined phone+SIM  */
4147       res = celliax_serial_write_AT_ack(p, "AT+CPBS=MT");
4148       if (res) {
4149         WARNINGA("AT+CPBS=MT failed, continue\n", CELLIAX_P_LOG);
4150       }
4151       /* How many entries in phonebook  */
4152       p->phonebook_querying = 1;
4153       res = celliax_serial_write_AT_ack(p, "AT+CPBR=?");
4154       if (res) {
4155         WARNINGA("AT+CPBR=? failed, continue\n", CELLIAX_P_LOG);
4156       }
4157       p->phonebook_querying = 0;
4158       /* list entries in phonebook, give the SIM the time to answer  */
4159       WARNINGA
4160         ("About to querying the cellphone phonebook, if the SIM do not answer may stuck here for 20 seconds... Don't worry.\n",
4161          CELLIAX_P_LOG);
4162       sprintf(list_command, "AT+CPBR=%d,%d", p->phonebook_first_entry,
4163               p->phonebook_last_entry);
4164       p->phonebook_listing = 1;
4165       res = celliax_serial_write_AT_expect_longtime(p, list_command, "OK");
4166       if (res) {
4167         WARNINGA("AT+CPBR=%d,%d failed, continue\n", CELLIAX_P_LOG,
4168                  p->phonebook_first_entry, p->phonebook_last_entry);
4169       }
4170       p->phonebook_listing = 0;
4171     }
4172   /*******************************************************************************************/
4173 #ifdef CELLIAX_LIBCSV
4174     if (fromvcf) {
4175       //TODO implementation here
4176     }
4177 #endif /* CELLIAX_LIBCSV */
4178 
4179   } else {
4180     ast_cli(fd, "\n\nfailed to open the directoriax.conf configuration file: %s\n", fn);
4181     ERRORA("failed to open the directoriax.conf configuration file: %s\n", CELLIAX_P_LOG,
4182            fn);
4183     return RESULT_FAILURE;
4184   }
4185 
4186   fclose(p->phonebook_writing_fp);
4187   //celliax_dir_create_extensions();
4188 
4189   return RESULT_SUCCESS;
4190 }
4191 
4192 #endif /* CELLIAX_DIR */
4193 
4194 #ifdef CELLIAX_FBUS2
4195 
celliax_serial_getstatus_FBUS2(struct celliax_pvt * p)4196 int celliax_serial_getstatus_FBUS2(struct celliax_pvt *p)
4197 {
4198   unsigned char MsgBuffer[7];
4199   int res;
4200   int how_many_reads = 0;
4201 
4202   PUSHA_UNLOCKA(&p->controldev_lock);
4203   LOKKA(&p->controldev_lock);
4204 
4205   MsgBuffer[0] = FBUS2_COMMAND_BYTE_1;
4206   MsgBuffer[1] = FBUS2_COMMAND_BYTE_2;
4207   MsgBuffer[2] = 0x00;
4208   MsgBuffer[3] = 0x03;
4209   MsgBuffer[4] = 0x00;
4210   MsgBuffer[5] = FBUS2_IS_LAST_FRAME;
4211   MsgBuffer[6] = celliax_serial_get_seqnum_FBUS2(p);
4212 
4213   if (option_debug > 1)
4214     DEBUGA_FBUS2("asking model, outseqnum %.2X \n", CELLIAX_P_LOG, MsgBuffer[6]);
4215   celliax_serial_write_FBUS2(p, MsgBuffer, 7, FBUS2_TYPE_MODEL_ASK);
4216   usleep(1000);
4217   res = celliax_serial_read_FBUS2(p);   //we don't have no monitor neither do_controldev_thread
4218   if (res == -1) {
4219     ERRORA("failed celliax_serial_read_FBUS2\n", CELLIAX_P_LOG);
4220     UNLOCKA(&p->controldev_lock);
4221     return -1;
4222   }
4223   while (res != MsgBuffer[6] && res != FBUS2_TYPE_MODEL_ANSWER) {
4224     usleep(1000);
4225     res = celliax_serial_read_FBUS2(p);
4226     how_many_reads++;
4227     if (res == -1) {
4228       ERRORA("failed celliax_serial_read_FBUS2\n", CELLIAX_P_LOG);
4229       UNLOCKA(&p->controldev_lock);
4230       return -1;
4231     }
4232     if (how_many_reads > 10) {
4233       ERRORA("no expected results in %d celliax_serial_read_FBUS2\n", CELLIAX_P_LOG,
4234              how_many_reads);
4235       UNLOCKA(&p->controldev_lock);
4236       return -1;
4237     }
4238   }
4239 
4240   UNLOCKA(&p->controldev_lock);
4241   POPPA_UNLOCKA(&p->controldev_lock);
4242   return 0;
4243 }
4244 
celliax_serial_sync_FBUS2(struct celliax_pvt * p)4245 int celliax_serial_sync_FBUS2(struct celliax_pvt *p)
4246 {
4247   unsigned char initc = 0x55;   /* FBUS2 initialization char */
4248   int c, rt;
4249   PUSHA_UNLOCKA(&p->controldev_lock);
4250   LOKKA(&p->controldev_lock);
4251   /*  init the link (sync receive uart) */
4252   for (c = 0; c < 55; c++) {    /* 55 times */
4253     usleep(10000);
4254     rt = write(p->controldevfd, &initc, 1);
4255     if (rt != 1) {
4256       ERRORA("serial error: %s", CELLIAX_P_LOG, strerror(errno));
4257       UNLOCKA(&p->controldev_lock);
4258       return -1;
4259     }
4260   }
4261   time(&p->celliax_serial_synced_timestamp);
4262   UNLOCKA(&p->controldev_lock);
4263   POPPA_UNLOCKA(&p->controldev_lock);
4264   return 0;
4265 }
4266 
celliax_serial_answer_FBUS2(struct celliax_pvt * p)4267 int celliax_serial_answer_FBUS2(struct celliax_pvt *p)
4268 {
4269   unsigned char MsgBuffer[6];
4270 
4271   celliax_serial_security_command_FBUS2(p);
4272 
4273   MsgBuffer[0] = FBUS2_COMMAND_BYTE_1;
4274   MsgBuffer[1] = FBUS2_COMMAND_BYTE_2;
4275   MsgBuffer[2] = FBUS2_SECURIY_CALL_COMMANDS;
4276   MsgBuffer[3] = FBUS2_SECURIY_CALL_COMMAND_ANSWER;
4277   MsgBuffer[4] = FBUS2_IS_LAST_FRAME;
4278   MsgBuffer[5] = celliax_serial_get_seqnum_FBUS2(p);
4279   if (option_debug > 1)
4280     DEBUGA_FBUS2("celliax_serial_answer_FBUS2, outseqnum %.2X \n", CELLIAX_P_LOG,
4281                  MsgBuffer[5]);
4282   celliax_serial_write_FBUS2(p, MsgBuffer, 6, FBUS2_TYPE_SECURITY);
4283   DEBUGA_FBUS2("FBUS2: sent commands to answer the call\n", CELLIAX_P_LOG);
4284   p->interface_state = AST_STATE_UP;    //FIXME
4285 
4286   return 0;
4287 }
4288 
celliax_serial_call_FBUS2(struct celliax_pvt * p,char * dstr)4289 int celliax_serial_call_FBUS2(struct celliax_pvt *p, char *dstr)
4290 {
4291   unsigned char MsgBufferNum[255];
4292   int i;
4293 
4294   celliax_serial_security_command_FBUS2(p);
4295 
4296   MsgBufferNum[0] = FBUS2_COMMAND_BYTE_1;
4297   MsgBufferNum[1] = FBUS2_COMMAND_BYTE_2;
4298   MsgBufferNum[2] = FBUS2_SECURIY_CALL_COMMANDS;
4299   MsgBufferNum[3] = FBUS2_SECURIY_CALL_COMMAND_CALL;
4300   for (i = 0; i < strlen(dstr); i++) {
4301     MsgBufferNum[4 + i] = dstr[i];
4302   }
4303   MsgBufferNum[4 + strlen(dstr)] = 0x00;    /* required by FBUS2 prot */
4304   MsgBufferNum[4 + strlen(dstr) + 1] = FBUS2_IS_LAST_FRAME;
4305   MsgBufferNum[4 + strlen(dstr) + 2] = celliax_serial_get_seqnum_FBUS2(p);
4306   if (option_debug > 1)
4307     DEBUGA_FBUS2("celliax_serial_call_FBUS2, outseqnum %.2X \n", CELLIAX_P_LOG,
4308                  MsgBufferNum[4 + strlen(dstr) + 2]);
4309   celliax_serial_write_FBUS2(p, MsgBufferNum, 5 + strlen(dstr) + 2, FBUS2_TYPE_SECURITY);
4310 
4311   p->phone_callflow = CALLFLOW_CALL_DIALING;
4312   p->interface_state = AST_STATE_DIALING;
4313   if (option_debug)
4314     DEBUGA_FBUS2("FBUS2: sent commands to call\n", CELLIAX_P_LOG);
4315   return 0;
4316 }
4317 
celliax_serial_hangup_FBUS2(struct celliax_pvt * p)4318 int celliax_serial_hangup_FBUS2(struct celliax_pvt *p)
4319 {
4320   unsigned char MsgBuffer[6];
4321 
4322   if (p->interface_state != AST_STATE_DOWN) {
4323     celliax_serial_security_command_FBUS2(p);
4324 
4325     MsgBuffer[0] = FBUS2_COMMAND_BYTE_1;
4326     MsgBuffer[1] = FBUS2_COMMAND_BYTE_2;
4327     MsgBuffer[2] = FBUS2_SECURIY_CALL_COMMANDS;
4328     MsgBuffer[3] = FBUS2_SECURIY_CALL_COMMAND_RELEASE;
4329     MsgBuffer[4] = FBUS2_IS_LAST_FRAME;
4330     MsgBuffer[5] = celliax_serial_get_seqnum_FBUS2(p);
4331 
4332     if (option_debug > 1)
4333       DEBUGA_FBUS2("celliax_serial_hangup_FBUS2, outseqnum %.2X \n", CELLIAX_P_LOG,
4334                    MsgBuffer[5]);
4335     celliax_serial_write_FBUS2(p, MsgBuffer, 6, FBUS2_TYPE_SECURITY);
4336 
4337     DEBUGA_FBUS2("FBUS2: sent commands to hangup the call\n", CELLIAX_P_LOG);
4338 
4339   }
4340   p->interface_state = AST_STATE_DOWN;  //FIXME
4341   p->phone_callflow = CALLFLOW_CALL_IDLE;   //FIXME
4342   return 0;
4343 }
4344 
celliax_serial_config_FBUS2(struct celliax_pvt * p)4345 int celliax_serial_config_FBUS2(struct celliax_pvt *p)
4346 {
4347   unsigned char MsgBuffer[6];
4348   int res;
4349   int how_many_reads = 0;
4350 
4351   MsgBuffer[0] = FBUS2_COMMAND_BYTE_1;
4352   MsgBuffer[1] = FBUS2_COMMAND_BYTE_2;
4353   MsgBuffer[2] = FBUS2_SECURIY_EXTENDED_COMMANDS;
4354   MsgBuffer[3] = FBUS2_SECURIY_EXTENDED_COMMAND_ON;
4355   MsgBuffer[4] = FBUS2_IS_LAST_FRAME;
4356   MsgBuffer[5] = celliax_serial_get_seqnum_FBUS2(p);
4357 
4358   if (option_debug > 1)
4359     DEBUGA_FBUS2("activating security commands for getting IMEI, outseqnum %.2X \n",
4360                  CELLIAX_P_LOG, MsgBuffer[5]);
4361   celliax_serial_write_FBUS2(p, MsgBuffer, 6, FBUS2_TYPE_SECURITY);
4362   res = celliax_serial_read_FBUS2(p);   //we don't have no monitor neither do_controldev_thread
4363   if (res == -1) {
4364     ERRORA("failed celliax_serial_read_FBUS2\n", CELLIAX_P_LOG);
4365     return -1;
4366   }
4367   while (res != MsgBuffer[5] && res != FBUS2_SECURIY_EXTENDED_COMMAND_ON) {
4368     usleep(1000);
4369     res = celliax_serial_read_FBUS2(p);
4370     how_many_reads++;
4371     if (res == -1) {
4372       ERRORA("failed celliax_serial_read_FBUS2\n", CELLIAX_P_LOG);
4373       return -1;
4374     }
4375     if (how_many_reads > 10) {
4376       ERRORA("no expected results in %d celliax_serial_read_FBUS2\n", CELLIAX_P_LOG,
4377              how_many_reads);
4378       return -1;
4379     }
4380   }
4381 
4382   MsgBuffer[0] = FBUS2_COMMAND_BYTE_1;
4383   MsgBuffer[1] = FBUS2_COMMAND_BYTE_2;
4384   MsgBuffer[2] = FBUS2_SECURIY_IMEI_COMMANDS;
4385   MsgBuffer[3] = FBUS2_SECURIY_IMEI_COMMAND_GET;
4386   MsgBuffer[4] = FBUS2_IS_LAST_FRAME;
4387   MsgBuffer[5] = celliax_serial_get_seqnum_FBUS2(p);
4388   if (option_debug > 1)
4389     DEBUGA_FBUS2("celliax_serial_get_IMEI_init_FBUS2, outseqnum %.2X \n", CELLIAX_P_LOG,
4390                  MsgBuffer[5]);
4391   celliax_serial_write_FBUS2(p, MsgBuffer, 6, FBUS2_TYPE_SECURITY);
4392   res = celliax_serial_read_FBUS2(p);   //we don't have no monitor neither do_controldev_thread
4393   if (res == -1) {
4394     ERRORA("failed celliax_serial_read_FBUS2\n", CELLIAX_P_LOG);
4395     return -1;
4396   }
4397   how_many_reads = 0;
4398   while (res != MsgBuffer[5] && res != CALLFLOW_GOT_IMEI) {
4399     usleep(1000);
4400     res = celliax_serial_read_FBUS2(p);
4401     how_many_reads++;
4402     if (res == -1) {
4403       ERRORA("failed celliax_serial_read_FBUS2\n", CELLIAX_P_LOG);
4404       return -1;
4405     }
4406     if (how_many_reads > 10) {
4407       ERRORA("no expected results in %d celliax_serial_read_FBUS2\n", CELLIAX_P_LOG,
4408              how_many_reads);
4409       //FIXME return -1;
4410       return 0;
4411     }
4412   }
4413 
4414   if (option_debug > 1)
4415     DEBUGA_FBUS2("xxxxx GOT IMEI xxxxx res=%d %.2X \n", CELLIAX_P_LOG, res, res);
4416 
4417   return 0;
4418 }
4419 
celliax_serial_get_seqnum_FBUS2(struct celliax_pvt * p)4420 int celliax_serial_get_seqnum_FBUS2(struct celliax_pvt *p)
4421 {
4422   if (p->seqnumfbus > FBUS2_SEQNUM_MAX || p->seqnumfbus < FBUS2_SEQNUM_MIN) {
4423     ERRORA("p->seqnumfbus: %2.X\n", CELLIAX_P_LOG, p->seqnumfbus);
4424     p->seqnumfbus = FBUS2_SEQNUM_MIN;
4425   }
4426 
4427   if (p->seqnumfbus == FBUS2_SEQNUM_MAX) {
4428     p->seqnumfbus = FBUS2_SEQNUM_MIN;
4429   } else {
4430     p->seqnumfbus++;
4431   }
4432   if (option_debug > 10)
4433     DEBUGA_FBUS2("sqnum: %2.X\n", CELLIAX_P_LOG, p->seqnumfbus);
4434   return p->seqnumfbus;
4435 }
4436 
celliax_serial_security_command_FBUS2(struct celliax_pvt * p)4437 int celliax_serial_security_command_FBUS2(struct celliax_pvt *p)
4438 {
4439   unsigned char MsgBuffer[6];
4440 
4441   MsgBuffer[0] = FBUS2_COMMAND_BYTE_1;
4442   MsgBuffer[1] = FBUS2_COMMAND_BYTE_2;
4443   MsgBuffer[2] = FBUS2_SECURIY_EXTENDED_COMMANDS;
4444   MsgBuffer[3] = FBUS2_SECURIY_EXTENDED_COMMAND_ON;
4445   MsgBuffer[4] = FBUS2_IS_LAST_FRAME;
4446   MsgBuffer[5] = celliax_serial_get_seqnum_FBUS2(p);
4447 
4448   if (option_debug > 1)
4449     DEBUGA_FBUS2("activating security commands, outseqnum %.2X \n", CELLIAX_P_LOG,
4450                  MsgBuffer[5]);
4451   celliax_serial_write_FBUS2(p, MsgBuffer, 6, FBUS2_TYPE_SECURITY);
4452   return 0;
4453 }
4454 
4455 /*!
4456  * \brief Write on the serial port for all the FBUS2 (old Nokia) functions
4457  * \param p celliax_pvt
4458  * \param len lenght of buffer2
4459  * \param buffer2 chars to be written
4460  *
4461  * Write on the serial port for all the FBUS2 (old Nokia) functions
4462  *
4463  * \return the number of chars written on the serial,
4464  * that can be different from len (or negative) in case of errors.
4465  */
celliax_serial_send_FBUS2(struct celliax_pvt * p,int len,unsigned char * mesg_ptr)4466 int celliax_serial_send_FBUS2(struct celliax_pvt *p, int len, unsigned char *mesg_ptr)
4467 {
4468   int ret;
4469   size_t actual = 0;
4470   unsigned char *mesg_ptr2 = mesg_ptr;
4471   PUSHA_UNLOCKA(&p->controldev_lock);
4472   LOKKA(&p->controldev_lock);
4473   do {
4474     ret = write(p->controldevfd, mesg_ptr, len - actual);
4475     if (ret < 0 && errno == EAGAIN)
4476       continue;
4477     if (ret < 0) {
4478       if (actual != len)
4479         ERRORA("celliax_serial_write error: %s", CELLIAX_P_LOG, strerror(errno));
4480       UNLOCKA(&p->controldev_lock);
4481       return -1;
4482     }
4483     actual += ret;
4484     mesg_ptr += ret;
4485     usleep(10000);
4486   } while (actual < len);
4487 
4488   UNLOCKA(&p->controldev_lock);
4489   POPPA_UNLOCKA(&p->controldev_lock);
4490   if (option_debug > 10) {
4491     int i;
4492     char debug_buf[1024];
4493     char *debug_buf_pos;
4494 
4495     memset(debug_buf, 0, 1024);
4496     debug_buf_pos = debug_buf;
4497 
4498     for (i = 0; i < len; i++) {
4499       debug_buf_pos += sprintf(debug_buf_pos, "[%.2X] ", mesg_ptr2[i]);
4500       if (debug_buf_pos > ((char *) &debug_buf + 1000))
4501         break;
4502     }
4503     DEBUGA_FBUS2("%s was sent down the wire\n", CELLIAX_P_LOG, debug_buf);
4504   }
4505 
4506   return 0;
4507 }
4508 
4509 /*!
4510  * \brief Flags as acknowledged an FBUS2 message previously sent
4511  * \param p celliax_pvt
4512  * \param seqnum identifier of the message to be acknowledged
4513  *
4514  * Called upon receiving an FBUS2 acknoledgement message, browse the fbus2_outgoing_list
4515  * looking for the seqnum sent FBUS2 message, and flags it as acknowledged.
4516  * (if an outgoing FBUS2 message is not aknowledged by the cellphone in a while,
4517  * it will be retransmitted)
4518  *
4519  * \return 0 on error, 1 otherwise
4520  */
celliax_serial_list_acknowledge_FBUS2(struct celliax_pvt * p,int seqnum)4521 int celliax_serial_list_acknowledge_FBUS2(struct celliax_pvt *p, int seqnum)
4522 {
4523   struct fbus2_msg *ptr;
4524 
4525   ptr = p->fbus2_outgoing_list;
4526   if (ptr == NULL) {
4527     ERRORA("fbus2_outgoing_list is NULL ?\n", CELLIAX_P_LOG);
4528     return -1;
4529   }
4530   PUSHA_UNLOCKA(&p->fbus2_outgoing_list_lock);
4531   LOKKA(&p->fbus2_outgoing_list_lock);
4532   while (ptr->next != NULL)
4533     ptr = ptr->next;
4534   while (ptr->acknowledged == 0) {
4535     if (ptr->seqnum == seqnum) {
4536       ptr->acknowledged = 1;
4537       if (option_debug > 1)
4538         DEBUGA_FBUS2("Acknowledgment to %.2X\n", CELLIAX_P_LOG, seqnum);
4539 
4540       DEBUGA_FBUS2("PREFREE OUTGOING list:\n", CELLIAX_P_LOG);
4541       celliax_serial_list_print_FBUS2(p, p->fbus2_outgoing_list);
4542       if (ptr->previous) {
4543         if (ptr->next) {
4544           ptr->previous->next = ptr->next;
4545         } else {
4546           ptr->previous->next = NULL;
4547         }
4548       }
4549       if (ptr->next) {
4550         if (ptr->previous) {
4551           ptr->next->previous = ptr->previous;
4552         } else {
4553           ptr->next->previous = NULL;
4554         }
4555       }
4556 
4557       if ((NULL == ptr->next) && (NULL == ptr->previous)) { /* bug catched by Wojciech Andralojc */
4558         if (option_debug > 1)
4559           DEBUGA_FBUS2("FREEING LAST\n", CELLIAX_P_LOG);
4560         p->fbus2_outgoing_list = NULL;
4561         p->fbus2_outgoing_list = celliax_serial_list_init_FBUS2(p);
4562       }
4563 
4564       free(ptr);
4565       DEBUGA_FBUS2("POSTFREE OUTGOING list:\n", CELLIAX_P_LOG);
4566       celliax_serial_list_print_FBUS2(p, p->fbus2_outgoing_list);
4567 
4568       break;
4569     }
4570     if (ptr->previous != NULL) {
4571       ptr = ptr->previous;
4572     } else {
4573       ERRORA
4574         ("The phone sent us an acknowledgement referring to a msg with a seqnum that is not in our sent list: %.2X\n",
4575          CELLIAX_P_LOG, seqnum);
4576       break;
4577     }
4578   }
4579   UNLOCKA(&p->fbus2_outgoing_list_lock);
4580   POPPA_UNLOCKA(&p->fbus2_outgoing_list_lock);
4581   return 0;
4582 }
4583 
4584 /*!
4585  * \brief Sends an FBUS2 message or resends it if it was not acknowledged
4586  * \param p celliax_pvt
4587  *
4588  * Called by celliax_serial_read_FBUS2, browse the fbus2_outgoing_list looking for FBUS2 messages to be sent,
4589  * or for FBUS2 messages previously sent but not yet acknoledged.
4590  * (if an outgoing FBUS2 message is not aknowledged by the cellphone in a while,
4591  * it will be retransmitted)
4592  *
4593  * \return 0 on error, 1 otherwise
4594  */
celliax_serial_send_if_time_FBUS2(struct celliax_pvt * p)4595 int celliax_serial_send_if_time_FBUS2(struct celliax_pvt *p)
4596 {
4597   struct fbus2_msg *ptr;
4598   struct timeval tv;
4599   struct timezone tz;
4600 
4601   gettimeofday(&tv, &tz);
4602   ptr = p->fbus2_outgoing_list;
4603   if (ptr == NULL) {
4604     ERRORA("fbus2_outgoing_list is NULL ?\n", CELLIAX_P_LOG);
4605     return -1;
4606   }
4607   while (ptr->next != NULL) {
4608     WARNINGA("fbus2_outgoing_list->next is not null ?\n", CELLIAX_P_LOG);
4609     ptr = ptr->next;            //FIXME what to do?
4610   }
4611   while (ptr->sent == 0 && ptr->acknowledged == 0) {
4612     if (ptr->previous != NULL) {
4613       ptr = ptr->previous;
4614     } else
4615       break;
4616   }
4617   while (ptr->sent == 1 && ptr->acknowledged == 0) {
4618     if (ptr->previous != NULL) {
4619       ptr = ptr->previous;
4620     } else
4621       break;
4622   }
4623   if (ptr->sent == 1 && ptr->acknowledged == 1) {
4624     if (ptr->next != NULL) {
4625       ptr = ptr->next;
4626     }
4627   }
4628   if (ptr->sent == 1 && ptr->acknowledged == 0 && ptr->msg > 0) {
4629     if ((tv.tv_sec * 1000 + tv.tv_usec / 1000) >
4630         ((ptr->tv_sec * 1000 + ptr->tv_usec / 1000) + 1000)) {
4631 
4632       PUSHA_UNLOCKA(&p->fbus2_outgoing_list_lock);
4633       LOKKA(&p->fbus2_outgoing_list_lock);
4634 
4635       if (ptr->sent == 1 && ptr->acknowledged == 0 && ptr->msg > 0) {   //retest, maybe has been changed?
4636         if ((tv.tv_sec * 1000 + tv.tv_usec / 1000) > ((ptr->tv_sec * 1000 + ptr->tv_usec / 1000) + 1000)) { //retest, maybe has been changed?
4637 
4638           if (option_debug > 1)
4639             DEBUGA_FBUS2("RESEND %.2X, passed %ld ms, sent %d times\n", CELLIAX_P_LOG,
4640                          ptr->seqnum,
4641                          ((tv.tv_sec * 1000 + tv.tv_usec / 1000) -
4642                           (ptr->tv_sec * 1000 + ptr->tv_usec / 1000)),
4643                          ptr->how_many_sent);
4644           if (ptr->how_many_sent > 9) {
4645             ERRORA("RESEND %.2X, passed %ld ms, sent %d times\n", CELLIAX_P_LOG,
4646                    ptr->seqnum,
4647                    ((tv.tv_sec * 1000 + tv.tv_usec / 1000) -
4648                     (ptr->tv_sec * 1000 + ptr->tv_usec / 1000)), ptr->how_many_sent);
4649 
4650             UNLOCKA(&p->fbus2_outgoing_list_lock);
4651             return -1;
4652           }
4653 
4654           celliax_serial_send_FBUS2(p, ptr->len, ptr->buffer);
4655           if (ptr->buffer[3] == FBUS2_ACK_BYTE) {
4656             if (option_debug > 1)
4657               DEBUGA_FBUS2("RESEND ACK, passed %ld ms, sent %d times\n", CELLIAX_P_LOG,
4658                            ((tv.tv_sec * 1000 + tv.tv_usec / 1000) -
4659                             (ptr->tv_sec * 1000 + ptr->tv_usec / 1000)),
4660                            ptr->how_many_sent);
4661             ptr->acknowledged = 1;
4662             ptr->msg = FBUS2_OUTGOING_ACK;
4663           }
4664           ptr->tv_sec = tv.tv_sec;
4665           ptr->tv_usec = tv.tv_usec;
4666           ptr->sent = 1;
4667           ptr->how_many_sent++;
4668           if (option_debug > 1) {
4669             DEBUGA_FBUS2("OUTGOING list:\n", CELLIAX_P_LOG);
4670             celliax_serial_list_print_FBUS2(p, p->fbus2_outgoing_list);
4671             DEBUGA_FBUS2("OUTGOING list END\n", CELLIAX_P_LOG);
4672           }
4673 
4674         }
4675       }
4676 
4677       UNLOCKA(&p->fbus2_outgoing_list_lock);
4678       POPPA_UNLOCKA(&p->fbus2_outgoing_list_lock);
4679     }
4680   }
4681   if (ptr->sent == 0 && ptr->acknowledged == 0 && ptr->msg > 0) {
4682 
4683     PUSHA_UNLOCKA(&p->fbus2_outgoing_list_lock);
4684     LOKKA(&p->fbus2_outgoing_list_lock);
4685 
4686     if (ptr->sent == 0 && ptr->acknowledged == 0 && ptr->msg > 0) { //retest, maybe has been changed?
4687 
4688       if (option_debug > 1)
4689         DEBUGA_FBUS2("SENDING 1st TIME %.2X\n", CELLIAX_P_LOG, ptr->seqnum);
4690       celliax_serial_send_FBUS2(p, ptr->len, ptr->buffer);
4691       if (ptr->buffer[3] == FBUS2_ACK_BYTE) {
4692         if (option_debug > 1)
4693           DEBUGA_FBUS2("SENDING 1st TIME ACK\n", CELLIAX_P_LOG);
4694         ptr->acknowledged = 1;
4695         ptr->msg = FBUS2_OUTGOING_ACK;
4696       }
4697       ptr->tv_sec = tv.tv_sec;
4698       ptr->tv_usec = tv.tv_usec;
4699       ptr->sent = 1;
4700       ptr->how_many_sent++;
4701       if (option_debug > 1) {
4702         DEBUGA_FBUS2("OUTGOING list:\n", CELLIAX_P_LOG);
4703         celliax_serial_list_print_FBUS2(p, p->fbus2_outgoing_list);
4704         DEBUGA_FBUS2("OUTGOING list END\n", CELLIAX_P_LOG);
4705       }
4706 
4707     }
4708 
4709     UNLOCKA(&p->fbus2_outgoing_list_lock);
4710     POPPA_UNLOCKA(&p->fbus2_outgoing_list_lock);
4711 
4712   }
4713   return 0;
4714 }
4715 
celliax_serial_write_FBUS2(struct celliax_pvt * p,unsigned char * MsgBuffer,int MsgLength,unsigned char MsgType)4716 int celliax_serial_write_FBUS2(struct celliax_pvt *p, unsigned char *MsgBuffer,
4717                                int MsgLength, unsigned char MsgType)
4718 {
4719   unsigned char buffer2[FBUS2_MAX_TRANSMIT_LENGTH + 10];
4720   unsigned char checksum = 0;
4721   int i, len;
4722   struct timeval tv;
4723   struct timezone tz;
4724 
4725   buffer2[0] = FBUS2_SERIAL_FRAME_ID;
4726   buffer2[1] = FBUS2_DEVICE_PHONE;  /* destination */
4727   buffer2[2] = FBUS2_DEVICE_PC; /* source */
4728   buffer2[3] = MsgType;
4729   buffer2[4] = 0x00;            /* required by protocol */
4730   buffer2[5] = MsgLength;
4731 
4732   memcpy(buffer2 + 6, MsgBuffer, MsgLength);
4733   len = MsgLength + 6;
4734 
4735   /* Odd messages require additional padding 0x00 byte */
4736   if (MsgLength % 2)
4737     buffer2[len++] = 0x00;      /* optional PaddingByte */
4738 
4739   checksum = 0;
4740   for (i = 0; i < len; i += 2)
4741     checksum ^= buffer2[i];
4742   buffer2[len++] = checksum;    /* ChkSum1 */
4743 
4744   checksum = 0;
4745   for (i = 1; i < len; i += 2)
4746     checksum ^= buffer2[i];
4747   buffer2[len++] = checksum;    /* ChkSum2 */
4748 
4749   if (option_debug > 10) {
4750     int i;
4751     char debug_buf[1024];
4752     char *debug_buf_pos;
4753 
4754     memset(debug_buf, 0, 1024);
4755     debug_buf_pos = debug_buf;
4756 
4757     for (i = 0; i < len; i++) {
4758       debug_buf_pos += sprintf(debug_buf_pos, "[%.2X] ", buffer2[i]);
4759       if (debug_buf_pos > (char *) (&debug_buf + 1000))
4760         break;
4761     }
4762     if (buffer2[3] == FBUS2_ACK_BYTE) {
4763       DEBUGA_FBUS2("%s to be written, ACK\n", CELLIAX_P_LOG, debug_buf);
4764     } else {
4765       DEBUGA_FBUS2("%s to be written\n", CELLIAX_P_LOG, debug_buf);
4766     }
4767   }
4768 
4769   gettimeofday(&tv, &tz);
4770 
4771   if (buffer2[3] != FBUS2_ACK_BYTE) {
4772     p->fbus2_outgoing_list = celliax_serial_list_init_FBUS2(p);
4773     p->fbus2_outgoing_list->msg = 11;
4774 
4775     p->fbus2_outgoing_list->len = len;
4776     for (i = 0; i < len; i++) {
4777       p->fbus2_outgoing_list->buffer[i] = buffer2[i];
4778     }
4779     p->fbus2_outgoing_list->seqnum = MsgBuffer[MsgLength - 1];
4780     if (option_debug > 1) {
4781       DEBUGA_FBUS2("OUTGOING LIST seqnum is %2.X\n", CELLIAX_P_LOG,
4782                    MsgBuffer[MsgLength - 1]);
4783 
4784       DEBUGA_FBUS2("OUTGOING list:\n", CELLIAX_P_LOG);
4785       celliax_serial_list_print_FBUS2(p, p->fbus2_outgoing_list);
4786       DEBUGA_FBUS2("OUTGOING list END\n", CELLIAX_P_LOG);
4787     }
4788   } else {
4789     usleep(100);
4790     celliax_serial_send_FBUS2(p, len, buffer2);
4791   }
4792 
4793   return 0;
4794 }
4795 
celliax_serial_send_ack_FBUS2(struct celliax_pvt * p,unsigned char MsgType,unsigned char MsgSequence)4796 int celliax_serial_send_ack_FBUS2(struct celliax_pvt *p, unsigned char MsgType,
4797                                   unsigned char MsgSequence)
4798 {
4799   unsigned char buffer2[2];
4800 
4801   buffer2[0] = MsgType;
4802   buffer2[1] = (MsgSequence - FBUS2_SEQNUM_MIN);
4803 
4804   if (option_debug > 1)
4805     DEBUGA_FBUS2("SENDING ACK to %2.X, seqack %2.X \n", CELLIAX_P_LOG, MsgSequence,
4806                  (MsgSequence - FBUS2_SEQNUM_MIN));
4807   /* Sending to phone */
4808   return celliax_serial_write_FBUS2(p, buffer2, 2, FBUS2_ACK_BYTE);
4809 }
4810 
celliax_serial_list_init_FBUS2(struct celliax_pvt * p)4811 struct fbus2_msg *celliax_serial_list_init_FBUS2(struct celliax_pvt *p)
4812 {
4813   struct fbus2_msg *list;
4814   list = p->fbus2_outgoing_list;
4815 
4816   PUSHA_UNLOCKA(&p->fbus2_outgoing_list_lock);
4817   LOKKA(&p->fbus2_outgoing_list_lock);
4818   if (list == NULL) {
4819     list = malloc(sizeof(*(list)));
4820     list->msg = 0;
4821     list->seqnum = 0;
4822     list->len = 0;
4823     list->acknowledged = 0;
4824     list->how_many_sent = 0;
4825     list->sent = 0;
4826     list->tv_sec = 0;
4827     list->tv_usec = 0;
4828     list->next = NULL;
4829     list->previous = NULL;
4830   }
4831   if (list->msg != 0) {
4832     struct fbus2_msg *new;
4833     new = malloc(sizeof(*new));
4834     new->msg = 0;
4835     new->seqnum = 0;
4836     new->len = 0;
4837     new->acknowledged = 0;
4838     new->how_many_sent = 0;
4839     new->sent = 0;
4840     new->tv_sec = 0;
4841     new->tv_usec = 0;
4842     new->next = NULL;
4843     new->previous = list;
4844     list->next = new;
4845     list = new;
4846   }
4847   UNLOCKA(&p->fbus2_outgoing_list_lock);
4848   POPPA_UNLOCKA(&p->fbus2_outgoing_list_lock);
4849   return list;
4850 }
4851 
celliax_serial_list_print_FBUS2(struct celliax_pvt * p,struct fbus2_msg * list)4852 int celliax_serial_list_print_FBUS2(struct celliax_pvt *p, struct fbus2_msg *list)
4853 {
4854   struct fbus2_msg *ptr;
4855   ptr = list;
4856   while (ptr) {
4857     if (option_debug > 3)
4858       DEBUGA_FBUS2
4859         ("PTR msg is: %d, seqnum is %.2X, tv_sec is %d, tv_usec is %d, acknowledged is: %d,"
4860          " sent is:%d, how_many_sent is: %d\n", CELLIAX_P_LOG, ptr->msg, ptr->seqnum,
4861          ptr->tv_sec, ptr->tv_usec, ptr->acknowledged, ptr->sent, ptr->how_many_sent);
4862     ptr = ptr->previous;
4863   }
4864   return 0;
4865 }
4866 
celliax_serial_read_FBUS2(struct celliax_pvt * p)4867 int celliax_serial_read_FBUS2(struct celliax_pvt *p)
4868 {
4869   int read_count;
4870   int select_err;
4871   fd_set read_fds;
4872   struct timeval timeout;
4873   int fbus_mesg = 0;
4874   int i;
4875 
4876   FD_ZERO(&read_fds);
4877   FD_SET(p->controldevfd, &read_fds);
4878   timeout.tv_sec = 0;
4879   timeout.tv_usec = 50000;
4880 
4881   if ((select_err = select(p->controldevfd + 1, &read_fds, NULL, NULL, &timeout)) > 0) {
4882     timeout.tv_sec = 0;         //reset the timeout, linux modify it
4883     timeout.tv_usec = 50000;    //reset the timeout, linux modify it
4884     PUSHA_UNLOCKA(&p->controldev_lock);
4885     LOKKA(&p->controldev_lock);
4886     while ((select_err =
4887             select(p->controldevfd + 1, &read_fds, NULL, NULL, &timeout)) > 0) {
4888       gettimeofday(&p->fbus2_list_tv, &p->fbus2_list_tz);
4889       read_count = read(p->controldevfd, p->rxm, 255);
4890 
4891       if (read_count == 0) {
4892         ERRORA
4893           ("read 0 bytes!!! Nenormalno! Marking this celliax_serial_device %s as dead, andif it is owned by a channel, hanging up. Maybe the phone is stuck, switched off, power down or battery exhausted\n",
4894            CELLIAX_P_LOG, p->controldevice_name);
4895         p->controldev_dead = 1;
4896         close(p->controldevfd);
4897         UNLOCKA(&p->controldev_lock);
4898         if (p->owner) {
4899           celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
4900           p->owner->hangupcause = AST_CAUSE_FAILURE;
4901         }
4902         return -1;
4903       }
4904       if (option_debug > 10) {
4905         int c;
4906         char debug_buf[1024];
4907         char *debug_buf_pos;
4908 
4909         memset(debug_buf, 0, 1024);
4910         debug_buf_pos = debug_buf;
4911         for (c = 0; c < read_count; c++) {
4912           debug_buf_pos += sprintf(debug_buf_pos, "[%.2X] ", p->rxm[c]);
4913           if (debug_buf_pos > (char *) (&debug_buf + 1000))
4914             break;
4915         }
4916         DEBUGA_FBUS2("%s READ AT seconds=%ld usec=%6ld read_count=%d\n", CELLIAX_P_LOG,
4917                      debug_buf, p->fbus2_list_tv.tv_sec, p->fbus2_list_tv.tv_usec,
4918                      read_count);
4919       }
4920 
4921       for (i = 0; i < read_count; i++) {
4922         if (p->rxm[i] == FBUS2_DEVICE_PHONE && p->rxm[i - 1] == FBUS2_DEVICE_PC
4923             && p->rxm[i - 2] == FBUS2_SERIAL_FRAME_ID) {
4924           /* if we have identified the start of an fbus2 frame sent to us by the phone */
4925           /* clean the array, copy into it the beginning of the frame, move the counter in the array after the last byte copied */
4926           memset(p->array, 0, 255);
4927           p->array[0] = FBUS2_SERIAL_FRAME_ID;
4928           p->array[1] = FBUS2_DEVICE_PC;
4929           p->arraycounter = 2;
4930         }
4931         if (p->rxm[i] == FBUS2_SERIAL_FRAME_ID && read_count == 1) {    /* quick hack to try to identify the lone char
4932                                                                            at the beginning a frame, often returned by
4933                                                                            ark3116 based datacables */
4934           /* if we have identified the start of an fbus2 frame sent to us by the phone */
4935           /* clean the array, copy into it the beginning of the frame, move the counter in the array after the last byte copied */
4936           memset(p->array, 0, 255);
4937           p->arraycounter = 0;
4938         }
4939 
4940         /* continue copying into the array, until... */
4941         p->array[p->arraycounter] = p->rxm[i];
4942         /* we reach the end of the incoming frame, its lenght is in the p->array[5] byte, plus overhead */
4943         if (p->arraycounter == p->array[5] + 7) {
4944           /* start categorizing frames */
4945           int seqnum;
4946           int known = 0;
4947 
4948           /* ACK frames are always of lenght 10, without padding */
4949           seqnum = p->array[p->arraycounter - 2];
4950           /* first step in categorizing frames, look at the general kind of frame, in p->array[3] */
4951           switch (p->array[3]) {
4952 /****************************************************************/
4953           case FBUS2_ACK_BYTE:
4954             /* this is an ACKnowledgement frame sent to us in reply to an item we sent, take note we were ACKnowledged, no need to resend the item */
4955             if (option_debug > 1)
4956               DEBUGA_FBUS2("INCOMING ACK, seqack %.2X \n", CELLIAX_P_LOG, seqnum);
4957             if (seqnum == 0x80) {   /* reset */
4958               seqnum = 0x00;
4959               DEBUGA_FBUS2
4960                 ("seqack was 0x80, interpreting as 0x00, first acknowledgement (session begin?) of our first sent item 0x40\n",
4961                  CELLIAX_P_LOG);
4962             }
4963             /* an ACK frame has the same seqnum as the item it acknowledge, minus 0x40, so here we obtain the seqnum of the item that has been ACKnowledged */
4964             fbus_mesg = seqnum + FBUS2_SEQNUM_MIN;
4965             /* take note that the item sent was ACKnowledged, so no need to resend it */
4966             celliax_serial_list_acknowledge_FBUS2(p, fbus_mesg);
4967             /* this frame has been categorized, bail out from the loop */
4968             known = 1;
4969             break;
4970 /****************************************************************/
4971           case FBUS2_TYPE_CALL_DIVERT:
4972             if (option_debug > 1)
4973               DEBUGA_FBUS2("CALL DIVERT SIGNALING seqnum %.2X \n", CELLIAX_P_LOG, seqnum);
4974             fbus_mesg = FBUS2_TYPE_CALL_DIVERT;
4975             /* this signal us that we have some settings in line divert, let's use it as activation of the line when we call */
4976             if (p->interface_state == AST_STATE_DIALING) {
4977               p->interface_state = AST_STATE_UP;
4978               p->phone_callflow = CALLFLOW_CALL_ACTIVE;
4979               ast_setstate(p->owner, AST_STATE_RINGING);
4980               celliax_queue_control(p->owner, AST_CONTROL_ANSWER);
4981               if (option_debug)
4982                 DEBUGA_FBUS2
4983                   ("call is active, I know it's not yet true, but 3310 do not give us remote answer signaling\n",
4984                    CELLIAX_P_LOG);
4985             }
4986             /* this frame has been categorized, bail out from the loop */
4987             known = 1;
4988             break;
4989 
4990 /****************************************************************/
4991             /* this kind of frames is an answer to "ask model" actions */
4992           case FBUS2_TYPE_MODEL_ANSWER:
4993             if (1) {
4994               int newline = 0;
4995               int c = i = 0;
4996               unsigned char model[10];
4997               for (i = 10; i < p->arraycounter; i++) {
4998                 if (p->array[i] == '\n')
4999                   newline++;
5000                 if (newline == 2) {
5001                   if (p->array[i] != '\n') {
5002                     model[c] = p->array[i];
5003                     c++;
5004                   }
5005                 }
5006                 if (newline == 3) {
5007                   break;
5008                 }
5009                 if (c == 9)
5010                   break;
5011               }
5012               model[c] = '\0';
5013               DEBUGA_FBUS2("FBUS2 PHONE MODEL is: %s, inseqnum %.2X \n", CELLIAX_P_LOG,
5014                            model, seqnum);
5015             }
5016             known = 1;
5017             fbus_mesg = FBUS2_TYPE_MODEL_ANSWER;
5018             break;
5019 /****************************************************************/
5020             /* this kind of frames is an answer to "security enabled" actions */
5021           case FBUS2_TYPE_SECURITY:
5022             switch (p->array[8]) {
5023               /* this subkind of frames is an answer to "security enabled" CALL actions */
5024             case FBUS2_SECURIY_CALL_COMMANDS:
5025               switch (p->array[9]) {
5026                 /* this sub-subkind of frames tell us that we answered the call */
5027               case FBUS2_SECURIY_CALL_COMMAND_ANSWER:
5028                 p->interface_state = AST_STATE_UP;
5029                 p->phone_callflow = CALLFLOW_CALL_ACTIVE;
5030 
5031                 /* set the channel state to UP, we've answered */
5032                 if (ast_setstate(p->owner, AST_STATE_UP)) {
5033                   ERRORA("ast_setstate failed, BAD\n", CELLIAX_P_LOG);
5034                 }
5035 
5036                 if (option_debug > 1)
5037                   DEBUGA_FBUS2("ANSWERED CALL, inseqnum %.2X \n", CELLIAX_P_LOG, seqnum);
5038                 known = 1;
5039                 break;
5040                 /* this sub-subkind of frames tell us that we released the call */
5041               case FBUS2_SECURIY_CALL_COMMAND_RELEASE:
5042                 p->interface_state = AST_STATE_DOWN;
5043                 p->phone_callflow = CALLFLOW_CALL_IDLE;
5044                 if (option_debug > 1)
5045                   DEBUGA_FBUS2("RELEASED CALL, inseqnum %.2X \n", CELLIAX_P_LOG, seqnum);
5046                 fbus_mesg = CALLFLOW_CALL_RELEASED;
5047                 known = 1;
5048                 break;
5049               }
5050               break;
5051               /* this subkind of frames is an answer to "enable security commands" action */
5052             case FBUS2_SECURIY_EXTENDED_COMMANDS:
5053               if (option_debug > 1)
5054                 DEBUGA_FBUS2("SECURITY EXTENDED COMMANDS ON, inseqnum %.2X \n",
5055                              CELLIAX_P_LOG, seqnum);
5056               fbus_mesg = FBUS2_SECURIY_EXTENDED_COMMAND_ON;
5057               known = 1;
5058               break;
5059               /* this subkind of frames is an answer to "get IMEI" action */
5060             case FBUS2_SECURIY_IMEI_COMMANDS:
5061               if (option_debug > 1)
5062                 DEBUGA_FBUS2("CALLFLOW_GOT_IMEI, inseqnum %.2X \n", CELLIAX_P_LOG,
5063                              seqnum);
5064               fbus_mesg = CALLFLOW_GOT_IMEI;
5065               known = 1;
5066               break;
5067             }
5068             break;
5069 /****************************************************************/
5070             /* this kind of frames is about SMSs */
5071           case FBUS2_TYPE_SMS:
5072             switch (p->array[9]) {
5073               /* this subkind of frames is about an INCOMING SMS */
5074             case FBUS2_SMS_INCOMING:
5075               if (option_debug > 1)
5076                 DEBUGA_FBUS2("SMS, inseqnum %.2X \n", CELLIAX_P_LOG, seqnum);
5077               known = 1;
5078               break;
5079             }
5080             break;
5081 /****************************************************************/
5082             /* this kind of frames is about PHONE CALLs */
5083           case FBUS2_TYPE_CALL:
5084             switch (p->array[9]) {
5085               int a;
5086               /* this subkind of frame is about the CALL has been HUNGUP */
5087             case FBUS2_CALL_HANGUP:
5088               p->interface_state = AST_STATE_DOWN;
5089               p->phone_callflow = CALLFLOW_CALL_IDLE;
5090               if (option_debug > 1)
5091                 DEBUGA_FBUS2("REMOTE PARTY HANG UP, inseqnum %.2X \n", CELLIAX_P_LOG,
5092                              seqnum);
5093               fbus_mesg = CALLFLOW_INCOMING_HANGUP;
5094               known = 1;
5095               break;
5096               /* this subkind of frame is about the remote CALLID (not signaled by 3310) */
5097             case FBUS2_CALL_CALLID:
5098               if (option_debug > 1)
5099                 DEBUGA_FBUS2("CALLID, inseqnum %.2X \n", CELLIAX_P_LOG, seqnum);
5100               memset(p->callid_name, 0, sizeof(p->callid_name));
5101               memset(p->callid_number, 0, sizeof(p->callid_number));
5102               for (a = 0; a < p->array[12]; a++) {
5103                 p->callid_number[a] = p->array[12 + a + 1];
5104               }
5105               for (a = 0; a < p->array[12 + 1 + p->array[12]] + 1; a++) {
5106                 p->callid_name[a] = p->array[12 + 1 + a + p->array[12] + 1];
5107               }
5108               if (option_debug > 1)
5109                 DEBUGA_FBUS2("CALLFLOW_INCOMING_CALLID: name is %s, number is %s\n",
5110                              CELLIAX_P_LOG,
5111                              p->callid_name[0] != 1 ? p->callid_name : "not available",
5112                              p->callid_number[0] ? p->callid_number : "not available");
5113               fbus_mesg = CALLFLOW_INCOMING_CALLID;
5114               p->phone_callflow = CALLFLOW_INCOMING_RING;
5115               p->interface_state = AST_STATE_RING;
5116               known = 1;
5117               break;
5118             }
5119             break;
5120 /****************************************************************/
5121             /* this kind of frames is about NETWORK STATUS */
5122           case FBUS2_TYPE_NETWORK_STATUS:
5123             switch (p->array[9]) {
5124               /* this subkind of frames is NETWORK STATUS REGISTERED */
5125             case FBUS2_NETWORK_STATUS_REGISTERED:
5126               if (option_debug > 1)
5127                 DEBUGA_FBUS2("NETWORK STATUS REGISTERED, inseqnum %.2X \n", CELLIAX_P_LOG,
5128                              seqnum);
5129               if (p->callid_name[0] == 0 && p->owner
5130                   && p->interface_state != AST_STATE_DOWN) {
5131                 p->interface_state = AST_STATE_DOWN;
5132                 p->phone_callflow = CALLFLOW_CALL_IDLE;
5133                 if (option_debug)
5134                   NOTICA("We think we are using a nokia3310, so NETWORK STATUS REGISTERED"
5135                          " is interpreted as REMOTE PARTY HANG UP during a call, because"
5136                          " Nokia 3310 give no hint about remote hangup. Nokia 3310"
5137                          " does not signal the CALLID, while other nokias at least put"
5138                          " callid_name[0]=1 (also if no callid was transmitted by remote"
5139                          " party), we use this lack of CALLID as a sign of 3310nness."
5140                          " Outside a call, or when CALLID has been signaled, NETWORK STATUS"
5141                          " REGISTERED is ignored.\n", CELLIAX_P_LOG);
5142                 fbus_mesg = CALLFLOW_INCOMING_HANGUP;
5143               }
5144               known = 1;
5145               break;
5146             }
5147             break;
5148 /****************************************************************/
5149             /* this kind of frames is about CALL STATUS */
5150           case FBUS2_TYPE_CALL_STATUS:
5151             switch (p->array[12]) {
5152               /* this subkind of frames is about CALL STATUS OFF */
5153             case FBUS2_CALL_STATUS_OFF:
5154               p->interface_state = AST_STATE_DOWN;
5155               p->phone_callflow = CALLFLOW_CALL_IDLE;
5156               if (option_debug > 1)
5157                 DEBUGA_FBUS2("STATUS call in progress OFF, inseqnum %.2X \n",
5158                              CELLIAX_P_LOG, seqnum);
5159               fbus_mesg = CALLFLOW_INCOMING_HANGUP;
5160               known = 1;
5161               break;
5162               /* this subkind of frames is about CALL STATUS ON */
5163             case FBUS2_CALL_STATUS_ON:
5164               if (option_debug > 1)
5165                 DEBUGA_FBUS2("STATUS call in progress ON, inseqnum %.2X \n",
5166                              CELLIAX_P_LOG, seqnum);
5167               known = 1;
5168               break;
5169             }
5170 /****************************************************************/
5171             break;
5172           }
5173 
5174           /* categorization of frame is ended, if it has not been recognized, whine */
5175           if (!known) {
5176             WARNINGA("FBUS2 MSG UNKNOWN, inseqnum %.2X\n", CELLIAX_P_LOG, seqnum);
5177           }
5178 
5179           /* let's print our frame */
5180           if (option_debug > 1) {
5181             int i;
5182             char debug_buf[1024];
5183             char *debug_buf_pos;
5184 
5185             memset(debug_buf, 0, 1024);
5186             debug_buf_pos = debug_buf;
5187             for (i = 0; i < p->arraycounter + 1; i++) {
5188               debug_buf_pos += sprintf(debug_buf_pos, "[%.2X] ", p->array[i]);
5189               if (debug_buf_pos > (char *) (&debug_buf + 1000))
5190                 break;
5191             }
5192             DEBUGA_FBUS2("%s is the RECEIVED FRAME inseqnum %.2X\n", CELLIAX_P_LOG,
5193                          debug_buf, seqnum);
5194           }
5195 
5196           /* if the frame we received is not an ACK frame, let's ACKnowledge it */
5197           if (p->array[0] == FBUS2_SERIAL_FRAME_ID && p->array[3] != FBUS2_ACK_BYTE) {
5198             celliax_serial_send_ack_FBUS2(p, p->array[3], seqnum);
5199           }
5200         }
5201         p->arraycounter++;
5202       }
5203     }
5204     UNLOCKA(&p->controldev_lock);
5205     POPPA_UNLOCKA(&p->controldev_lock);
5206   }
5207   /* oooops, select returned error, got a kill/cancel or problems with the serial file descriptor */
5208   if (select_err == -1) {
5209     if (errno != EINTR) {
5210       ERRORA
5211         ("select returned -1 on %s, marking controldev as dead, errno was: %d, error was: %s\n",
5212          CELLIAX_P_LOG, p->controldevice_name, errno, strerror(errno));
5213       p->controldev_dead = 1;
5214       close(p->controldevfd);
5215       if (p->owner)
5216         celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
5217       return -1;
5218     } else {
5219       WARNINGA("select returned -1 on %s, errno was: %d, EINTR, error was: %s\n",
5220                CELLIAX_P_LOG, p->controldevice_name, errno, strerror(errno));
5221       return 0;
5222     }
5223   }
5224   /* OK, reading done, let's browse the list of pending frames to be sent, and act on it */
5225   if (celliax_serial_send_if_time_FBUS2(p)) {
5226     ERRORA("celliax_serial_send_if_time_FBUS2 failed!\n", CELLIAX_P_LOG);
5227     return -1;
5228   }
5229 
5230   if (fbus_mesg == CALLFLOW_INCOMING_HANGUP) {
5231     if (p->owner) {
5232       celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
5233       DEBUGA_FBUS2("phone call ended\n", CELLIAX_P_LOG);
5234     }
5235   }
5236 
5237   return fbus_mesg;             //FIXME breaks the convention of returning 0 on success
5238 }
5239 
5240 #endif /* CELLIAX_FBUS2 */
5241 
5242 #ifdef CELLIAX_CVM
5243 
celliax_serial_sync_CVM_BUSMAIL(struct celliax_pvt * p)5244 int celliax_serial_sync_CVM_BUSMAIL(struct celliax_pvt *p)
5245 {
5246   usleep(1000);                 /* 1msec */
5247   time(&p->celliax_serial_synced_timestamp);
5248   return 0;
5249 }
5250 
celliax_serial_answer_CVM_BUSMAIL(struct celliax_pvt * p)5251 int celliax_serial_answer_CVM_BUSMAIL(struct celliax_pvt *p)
5252 {
5253   if (AST_STATE_RING == p->interface_state) {
5254     DEBUGA_CVM("Sending commands to answer an incomming call...\n", CELLIAX_P_LOG);
5255     celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_CONNECT_REQ, 0, NULL);
5256 
5257   } else {
5258     DEBUGA_CVM
5259       ("SKIPPING Sending commands to answer an incomming call, because: !AST_STATE_RING\n",
5260        CELLIAX_P_LOG);
5261   }
5262 
5263   return 0;
5264 }
5265 
celliax_serial_call_CVM_BUSMAIL(struct celliax_pvt * p,char * dstr)5266 int celliax_serial_call_CVM_BUSMAIL(struct celliax_pvt *p, char *dstr)
5267 {
5268   unsigned char bCallType = 0x01;   /* INTERNAL */
5269 
5270   unsigned char DialReqBuff[2];
5271 
5272   celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_SETUP_REQ, sizeof(bCallType),
5273                                              &bCallType);
5274 
5275   while (AST_STATE_DOWN == p->interface_state) {
5276     usleep(10000);              //10msec
5277   }
5278 
5279   if (AST_STATE_DIALING == p->interface_state) {
5280     /* as for now, we only support internal calls */
5281     /* "0" - call speaker phone */
5282     /* "1" - call handset #1 */
5283     /* "2" - call handset #2 */
5284     /* ... */
5285 
5286     DialReqBuff[0] = 1;         /* number of digits to send */
5287     DialReqBuff[1] = dstr[0];   /* digit to send */
5288 
5289     celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_KEYPAD_REQ, 2, DialReqBuff);
5290   }
5291 
5292   if (option_debug)
5293     NOTICA("CVM_BUSMAIL: sent commands to call\n", CELLIAX_P_LOG);
5294   return 0;
5295 }
5296 
celliax_serial_hangup_CVM_BUSMAIL(struct celliax_pvt * p)5297 int celliax_serial_hangup_CVM_BUSMAIL(struct celliax_pvt *p)
5298 {
5299   unsigned char bReason = 0x0;  /* Normal hang-up */
5300 
5301   if (p->interface_state != AST_STATE_DOWN) {
5302     celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_RELEASE_REQ, sizeof(bReason),
5303                                                &bReason);
5304 
5305     DEBUGA_CVM("CVM_BUSMAIL: sent commands to hangup the call\n", CELLIAX_P_LOG);
5306 
5307   } else {
5308     DEBUGA_CVM("CVM_BUSMAIL: sent commands to hangup skipped because: AST_STATE_DOWN\n",
5309                CELLIAX_P_LOG);
5310   }
5311 
5312   return 0;
5313 }
5314 
celliax_serial_config_CVM_BUSMAIL(struct celliax_pvt * p)5315 int celliax_serial_config_CVM_BUSMAIL(struct celliax_pvt *p)
5316 {
5317   int res;
5318   int how_many_reads = 0;
5319   unsigned char SubcriptionNo = p->cvm_subsc_no;
5320   unsigned char RegistartionData[5];
5321 
5322   p->cvm_lock_state = CVM_UNKNOWN_LOCK_STATE;
5323   p->cvm_register_state = CVM_UNKNOWN_REGISTER_STATE;
5324 
5325   PUSHA_UNLOCKA(&p->controldev_lock);
5326   CVM_LOKKA(&p->controldev_lock);
5327 
5328   if (option_debug > 1)
5329     DEBUGA_CVM("Try to init communication with CVM...\n", CELLIAX_P_LOG);
5330 
5331   /* CVM after reset sends SABM CTRL frame, let's assume that CVM already sent it, that's the reply... */
5332   celliax_serial_send_ctrl_frame_CVM_BUSMAIL(p,
5333                                              BUSMAIL_HEADER_CTRL_FRAME |
5334                                              BUSMAIL_HEADER_CTRL_UN_FRAME |
5335                                              BUSMAIL_HEADER_UNID_SABM);
5336   /*  usleep(10000);   *//* 10ms */
5337 
5338   /* Now we are sending SABM CTRL frame, if CVM is out there, it should reply... */
5339   celliax_serial_send_ctrl_frame_CVM_BUSMAIL(p,
5340                                              BUSMAIL_HEADER_CTRL_FRAME |
5341                                              BUSMAIL_HEADER_CTRL_UN_FRAME |
5342                                              BUSMAIL_HEADER_UNID_SABM |
5343                                              (BUSMAIL_HEADER_PF_BIT_MASK & 0xFF));
5344 //  usleep(1000);
5345 
5346   res = celliax_serial_read_CVM_BUSMAIL(p); //we don't have no monitor neither do_controldev_thread
5347 
5348   DEBUGA_CVM("celliax_serial_read_CVM_BUSMAIL res= %X, expected %X\n", CELLIAX_P_LOG, res,
5349              (BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_UN_FRAME |
5350               BUSMAIL_HEADER_SABM));
5351 
5352   if (res == -1) {
5353     ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
5354     CVM_UNLOCKA(&p->controldev_lock);
5355     return -1;
5356   }
5357 
5358   how_many_reads = 0;
5359 
5360   while ((res & 0xF0) !=
5361          (BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_UN_FRAME | BUSMAIL_HEADER_SABM))
5362   {
5363 
5364     usleep(1000);
5365     res = celliax_serial_read_CVM_BUSMAIL(p);
5366     how_many_reads++;
5367 
5368     if (res == -1) {
5369       ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
5370       CVM_UNLOCKA(&p->controldev_lock);
5371       return -1;
5372     }
5373 
5374     if (how_many_reads > 10) {
5375       ERRORA("no expected results in %d celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG,
5376              how_many_reads);
5377 
5378       ERRORA("Unable to initialize cmmunication with CVM...\n", CELLIAX_P_LOG);
5379 
5380       CVM_UNLOCKA(&p->controldev_lock);
5381       return -1;
5382     }
5383   }
5384 
5385   DEBUGA_CVM("Communication with CVM initialized successfully...\n", CELLIAX_P_LOG);
5386 
5387   DEBUGA_CVM("Attempt to lock to FP...\n", CELLIAX_P_LOG);
5388 
5389   /* Try to connect to FP, try to lock to FP, maybe we registered with it in the past... */
5390   /* CVM can hold up to 2 subscriptions in its EEPROM, celliax.conf contains number we should try */
5391   /* eg. cvm_subscription_no = 1 */
5392 
5393   celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_LOCK_REQ, sizeof(SubcriptionNo),
5394                                              &SubcriptionNo);
5395 
5396   usleep(10000);
5397 
5398   res = celliax_serial_read_CVM_BUSMAIL(p); //we don't have no monitor neither do_controldev_thread
5399 
5400   if (res == -1) {
5401     ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
5402     CVM_UNLOCKA(&p->controldev_lock);
5403     return -1;
5404   }
5405 
5406   how_many_reads = 0;
5407 
5408   while (CVM_UNKNOWN_LOCK_STATE == p->cvm_lock_state) {
5409 
5410 /*
5411     if (0 == (how_many_reads % 10))
5412     {
5413       DEBUGA_CVM("Attempt to lock to FP... %d\n", CELLIAX_P_LOG, how_many_reads/10 );
5414       celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_LOCK_REQ, sizeof(SubcriptionNo) ,&SubcriptionNo);
5415     }
5416 */
5417 
5418     usleep(100000);
5419 
5420     res = celliax_serial_read_CVM_BUSMAIL(p);
5421     how_many_reads++;
5422 
5423     if (res == -1) {
5424       ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
5425       CVM_UNLOCKA(&p->controldev_lock);
5426       return -1;
5427     }
5428 
5429     if (how_many_reads > 50) {
5430       ERRORA("no expected results in %d celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG,
5431              how_many_reads);
5432 
5433       ERRORA("Unable to lock to FP...\n", CELLIAX_P_LOG);
5434       break;
5435     }
5436   }
5437 
5438   if (CVM_LOCKED_TO_FP == p->cvm_lock_state) {
5439     DEBUGA_CVM("CVM locked to FP successfully...\n", CELLIAX_P_LOG);
5440   } else {
5441     DEBUGA_CVM("Lock to FP failed, Attempt to register to FP...\n", CELLIAX_P_LOG);
5442 
5443     RegistartionData[0] = SubcriptionNo;
5444     RegistartionData[1] = 0xFF;
5445     RegistartionData[2] = 0xFF;
5446 
5447     if (1 == SubcriptionNo) {
5448       RegistartionData[3] =
5449         (((p->cvm_subsc_1_pin[3] - 0x30) & 0x0F) << 4) | ((p->cvm_subsc_1_pin[2] -
5450                                                            0x30) & 0x0F);
5451       RegistartionData[4] =
5452         (((p->cvm_subsc_1_pin[1] - 0x30) & 0x0F) << 4) | ((p->cvm_subsc_1_pin[0] -
5453                                                            0x30) & 0x0F);
5454     } else {
5455       RegistartionData[3] =
5456         (((p->cvm_subsc_2_pin[3] - 0x30) & 0x0F) << 4) | ((p->cvm_subsc_2_pin[2] -
5457                                                            0x30) & 0x0F);
5458       RegistartionData[4] =
5459         (((p->cvm_subsc_2_pin[1] - 0x30) & 0x0F) << 4) | ((p->cvm_subsc_2_pin[0] -
5460                                                            0x30) & 0x0F);
5461     }
5462 
5463     celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_ACCESS_RIGHTS_REQ,
5464                                                sizeof(RegistartionData),
5465                                                RegistartionData);
5466 
5467     usleep(100000);
5468 
5469     res = celliax_serial_read_CVM_BUSMAIL(p);   //we don't have no monitor neither do_controldev_thread
5470 
5471     if (res == -1) {
5472       ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
5473       CVM_UNLOCKA(&p->controldev_lock);
5474       return -1;
5475     }
5476 
5477     how_many_reads = 0;
5478 
5479     while (CVM_UNKNOWN_REGISTER_STATE == p->cvm_register_state) {
5480 
5481       if (0 == (how_many_reads % 50)) {
5482         DEBUGA_CVM("Attempt to register to FP... %d\n", CELLIAX_P_LOG,
5483                    how_many_reads / 10);
5484         celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_ACCESS_RIGHTS_REQ,
5485                                                    sizeof(RegistartionData),
5486                                                    RegistartionData);
5487       }
5488 
5489       /* up to 5 minutes for registration.... */
5490       usleep(1000000);
5491       res = celliax_serial_read_CVM_BUSMAIL(p);
5492       how_many_reads++;
5493 
5494       if (res == -1) {
5495         ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
5496         CVM_UNLOCKA(&p->controldev_lock);
5497         return -1;
5498       }
5499 
5500       if (how_many_reads > 300) {
5501         ERRORA("no expected results in %d celliax_serial_read_CVM_BUSMAIL\n",
5502                CELLIAX_P_LOG, how_many_reads);
5503 
5504         ERRORA("Unable to communication with CVM...\n", CELLIAX_P_LOG);
5505 
5506         CVM_UNLOCKA(&p->controldev_lock);
5507         return -1;
5508       }
5509     }
5510 
5511     if (CVM_REGISTERED_TO_FP != p->cvm_register_state) {
5512       ERRORA("Unable to register to FP...\n", CELLIAX_P_LOG);
5513 
5514       CVM_UNLOCKA(&p->controldev_lock);
5515       return -1;
5516 
5517     } else {
5518       DEBUGA_CVM("CVM registered to FP successfully...\n", CELLIAX_P_LOG);
5519       DEBUGA_CVM("Attempt to lock to FP...\n", CELLIAX_P_LOG);
5520 
5521       /* Try to connect to FP, try to lock to FP, maybe we registered with it in the past... */
5522       /* CVM can hold up to 2 subscriptions in its EEPROM, celliax.conf contains number we should try */
5523       /* eg. cvm_subscription_no = 1 */
5524 
5525       celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_LOCK_REQ,
5526                                                  sizeof(SubcriptionNo), &SubcriptionNo);
5527 
5528       usleep(10000);
5529 
5530       res = celliax_serial_read_CVM_BUSMAIL(p); //we don't have no monitor neither do_controldev_thread
5531 
5532       if (res == -1) {
5533         ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
5534         CVM_UNLOCKA(&p->controldev_lock);
5535         return -1;
5536       }
5537 
5538       how_many_reads = 0;
5539 
5540       while (CVM_UNKNOWN_LOCK_STATE == p->cvm_lock_state) {
5541 
5542         if (0 == (how_many_reads % 10)) {
5543           DEBUGA_CVM("Attempt to lock to FP... %d\n", CELLIAX_P_LOG, how_many_reads / 10);
5544           celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_ACCESS_RIGHTS_REQ,
5545                                                      sizeof(RegistartionData),
5546                                                      RegistartionData);
5547         }
5548 
5549         usleep(10000);
5550         res = celliax_serial_read_CVM_BUSMAIL(p);
5551         how_many_reads++;
5552 
5553         if (res == -1) {
5554           ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
5555           CVM_UNLOCKA(&p->controldev_lock);
5556           return -1;
5557         }
5558 
5559         if (how_many_reads > 100) {
5560           ERRORA("no expected results in %d celliax_serial_read_CVM_BUSMAIL\n",
5561                  CELLIAX_P_LOG, how_many_reads);
5562 
5563           ERRORA("Unable to communication with CVM...\n", CELLIAX_P_LOG);
5564 
5565           CVM_UNLOCKA(&p->controldev_lock);
5566           return -1;
5567         }
5568       }
5569 
5570       if (CVM_LOCKED_TO_FP != p->cvm_lock_state) {
5571         ERRORA("Unable to lock to FP...\n", CELLIAX_P_LOG);
5572 
5573         CVM_UNLOCKA(&p->controldev_lock);
5574         return -1;
5575       } else {
5576         DEBUGA_CVM("CVM locked to FP successfully...\n", CELLIAX_P_LOG);
5577       }
5578     }
5579   }
5580 
5581   usleep(100000);
5582 
5583   CVM_UNLOCKA(&p->controldev_lock);
5584   POPPA_UNLOCKA(&p->controldev_lock);
5585   return 0;
5586 
5587 }
5588 
celliax_serial_read_CVM_BUSMAIL(struct celliax_pvt * p)5589 int celliax_serial_read_CVM_BUSMAIL(struct celliax_pvt *p)
5590 {
5591   int read_count;
5592   int select_err;
5593   fd_set read_fds;
5594   struct timeval timeout;
5595   int cvm_busmail_mesg = 0;
5596   unsigned char busmail_crc = 0;
5597   unsigned char MsgCrc = 0;
5598   unsigned char MsgHeader = 0;
5599   unsigned char MsgTxSeqNo = 0;
5600   unsigned char MsgRxSeqNo = 0;
5601   unsigned char MsgTaskId = 0;
5602   unsigned char MsgProgId = 0;
5603   unsigned char MsgPrimitiveLSB = 0;
5604   unsigned char MsgPrimitiveMSB = 0;
5605   unsigned int MsgPrimitive = 0;
5606 
5607   int i = 0;
5608 
5609   FD_ZERO(&read_fds);
5610   FD_SET(p->controldevfd, &read_fds);
5611   timeout.tv_sec = 0;
5612   timeout.tv_usec = 10000;
5613 
5614   if ((select_err = select(p->controldevfd + 1, &read_fds, NULL, NULL, &timeout)) > 0) {
5615     timeout.tv_sec = 0;         //reset the timeout, linux modify it
5616     timeout.tv_usec = 10000;    //reset the timeout, linux modify it
5617     PUSHA_UNLOCKA(&p->controldev_lock);
5618     CVM_LOKKA(&p->controldev_lock);
5619 
5620     while ((select_err =
5621             select(p->controldevfd + 1, &read_fds, NULL, NULL, &timeout)) > 0) {
5622       gettimeofday(&p->cvm_busmail_list_tv, &p->cvm_busmail_list_tz);
5623       read_count = read(p->controldevfd, p->rxm, 255);
5624 
5625       if (read_count == 0) {
5626         ERRORA
5627           ("read 0 bytes!!! Nenormalno! Marking this celliax_serial_device %s as dead, andif it is owned by a channel, hanging up. Maybe the CVM is stuck, switched off or power down.\n",
5628            CELLIAX_P_LOG, p->controldevice_name);
5629 
5630         p->controldev_dead = 1;
5631         close(p->controldevfd);
5632         CVM_UNLOCKA(&p->controldev_lock);
5633 
5634         if (p->owner)
5635           celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
5636         return -1;
5637       }
5638 
5639       if (option_debug > 10) {
5640         char debug_buf[1024];
5641         char *debug_buf_pos;
5642 
5643         memset(debug_buf, 0, 1024);
5644         debug_buf_pos = debug_buf;
5645         for (i = 0; i < read_count; i++) {
5646           debug_buf_pos += sprintf(debug_buf_pos, "[%.2X] ", p->rxm[i]);
5647           if (debug_buf_pos > (char *) (&debug_buf + 1000))
5648             break;
5649         }
5650 
5651         DEBUGA_CVM("%s READ AT seconds=%ld usec=%6ld read_count=%d\n", CELLIAX_P_LOG,
5652                    debug_buf, p->cvm_busmail_list_tv.tv_sec,
5653                    p->cvm_busmail_list_tv.tv_usec, read_count);
5654       }
5655 
5656       for (i = 0; i < read_count; i++) {
5657         if (p->rxm[i] == BUSMAIL_SOF) {
5658           /* if we have identified the start of an busmail frame sent to us by the CVM */
5659           /* clean the array, copy into it the beginning of the frame, move the counter in the array after the last byte copied */
5660           memset(p->array, 0, 255);
5661           p->array[0] = p->rxm[i];
5662           p->arraycounter = 1;
5663         }
5664 
5665         /* buffer overload protection */
5666         if (255 == p->arraycounter) {
5667           p->arraycounter = 1;
5668         }
5669 
5670         /* continue copying into the array, until... */
5671         p->array[p->arraycounter - 1] = p->rxm[i];
5672 
5673         /* we reach the end of the incoming frame, its lenght is in the p->array[BUSMAIL_OFFSET_LEN_LSB] byte, plus overhead */
5674         if (p->arraycounter == p->array[BUSMAIL_OFFSET_LEN_LSB] + 4) {
5675 
5676           tcflush(p->controldevfd, TCIFLUSH);   /* PL2303HX bug? */
5677           /* start categorizing frames */
5678 
5679           if (option_debug > 10) {
5680             char debug_buf[1024];
5681             char *debug_buf_pos;
5682 
5683             memset(debug_buf, 0, 1024);
5684             debug_buf_pos = debug_buf;
5685 
5686             for (i = 0; i < p->arraycounter; i++) {
5687               debug_buf_pos += sprintf(debug_buf_pos, "[%.2X] ", p->array[i]);
5688               if (debug_buf_pos > (char *) (&debug_buf + 1000))
5689                 break;
5690             }
5691 
5692             DEBUGA_CVM("%s was received, Starting to categorize this frame\n",
5693                        CELLIAX_P_LOG, debug_buf);
5694           }
5695 
5696           int known = 0;
5697           int j = 0;
5698 
5699           busmail_crc = 0;
5700           MsgCrc = p->array[p->arraycounter - 1];
5701 
5702           busmail_crc = (unsigned char) (p->array[BUSMAIL_OFFSET_HEADER] + busmail_crc);
5703 
5704           for (j = BUSMAIL_OFFSET_MAIL; j < (p->arraycounter - 1); j++) {
5705             busmail_crc = (unsigned char) (p->array[j] + busmail_crc);
5706           }
5707 
5708           if (busmail_crc != MsgCrc) {
5709             WARNINGA("BUSMAIL MSG CRC FAILED!, MsgCrc %.2X, calcd %.2X, dropping frame\n",
5710                      CELLIAX_P_LOG, MsgCrc, busmail_crc);
5711           } else {
5712             /* first step in categorizing frames, look at the general kind of frame, in p->array[BUSMAIL_OFFSET_HEADER] */
5713             if (option_debug > 1)
5714               DEBUGA_CVM("BUSMAIL MSG CRC, MsgCrc %.2X, calcd %.2X...\n", CELLIAX_P_LOG,
5715                          MsgCrc, busmail_crc);
5716 
5717             MsgHeader = p->array[BUSMAIL_OFFSET_HEADER];
5718             cvm_busmail_mesg = MsgHeader;
5719 
5720             switch (MsgHeader & BUSMAIL_HEADER_IC_BIT_MASK) {
5721             case BUSMAIL_HEADER_INFO_FRAME:
5722               /* analyzis of frame header */
5723               MsgTxSeqNo = ((MsgHeader & BUSMAIL_HEADER_TXSEQ_MASK) >> 4);
5724               MsgRxSeqNo = ((MsgHeader & BUSMAIL_HEADER_RXSEQ_MASK));
5725 
5726               if (option_debug > 1)
5727                 DEBUGA_CVM("BUSMAIL_HEADER_INFO_FRAME TxSeq %X, RxSeq %X\n",
5728                            CELLIAX_P_LOG, MsgTxSeqNo, MsgRxSeqNo);
5729 
5730               if (((p->busmail_rxseq_cvm_last + 1) & 0x7) != MsgTxSeqNo) {
5731                 /* some CVM frames are missing, TxSeq of this frame is higher then expected */
5732                 /* reject, I expected p->busmail_rxseq_cvm_last + 1, resend it to me, please */
5733 
5734                 WARNINGA("CVM TxSeq %X, does not match expected value %X\n",
5735                          CELLIAX_P_LOG, MsgTxSeqNo,
5736                          (p->busmail_rxseq_cvm_last + 1) & 0x7);
5737 
5738 //                celliax_serial_send_ctrl_frame_CVM_BUSMAIL(p, BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_SU_FRAME | BUSMAIL_HEADER_SUID_REJ);
5739 
5740                 if (((p->busmail_rxseq_cvm_last) & 0x7) == MsgTxSeqNo) {
5741 
5742                   WARNINGA
5743                     ("It looks like our ACK to this frame was MIA :), lets ACK the frame one more time...\n",
5744                      CELLIAX_P_LOG);
5745 
5746                   /* if the frame we received informs us that other side is waiting for ACK, let's ACK it */
5747                   /* even if it is unknown to us */
5748                   if (p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_PF_BIT_MASK) {
5749                     if (BUSMAIL_HEADER_SABM ==
5750                         (p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_SABM_MASK)) {
5751                       celliax_serial_send_ctrl_frame_CVM_BUSMAIL(p, (unsigned char)
5752                                                                  (BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_UN_FRAME | BUSMAIL_HEADER_UNID_SABM));
5753                     } else {
5754                       celliax_serial_send_ctrl_frame_CVM_BUSMAIL(p, (unsigned char)
5755                                                                  (BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_SU_FRAME | BUSMAIL_HEADER_SUID_RR));
5756                     }
5757                   }
5758                 }
5759 
5760                 break;
5761               } else {
5762                 /* we expected packet with this seq no. */
5763                 /* CVM ACKed our frames with info frame */
5764                 celliax_serial_list_acknowledge_CVM_BUSMAIL(p, MsgRxSeqNo);
5765 
5766                 /* save it but limit it to 3 bits only (valid values: 0-7) */
5767                 p->busmail_rxseq_cvm_last = MsgTxSeqNo;
5768                 p->busmail_rxseq_cvm_last &= 0x7;
5769 
5770                 /* if the frame we received informs us that other side is waiting for ACK, let's ACK it */
5771                 /* even if it is unknown to us */
5772                 if (p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_PF_BIT_MASK) {
5773                   if (BUSMAIL_HEADER_SABM ==
5774                       (p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_SABM_MASK)) {
5775                     celliax_serial_send_ctrl_frame_CVM_BUSMAIL(p, (unsigned char)
5776                                                                (BUSMAIL_HEADER_CTRL_FRAME
5777                                                                 |
5778                                                                 BUSMAIL_HEADER_CTRL_UN_FRAME
5779                                                                 |
5780                                                                 BUSMAIL_HEADER_UNID_SABM));
5781                   } else {
5782                     celliax_serial_send_ctrl_frame_CVM_BUSMAIL(p, (unsigned char)
5783                                                                (BUSMAIL_HEADER_CTRL_FRAME
5784                                                                 |
5785                                                                 BUSMAIL_HEADER_CTRL_SU_FRAME
5786                                                                 |
5787                                                                 BUSMAIL_HEADER_SUID_RR));
5788                   }
5789                 }
5790 
5791               }
5792 
5793               /* frame header OK, let's see what's inside mail field */
5794               MsgTaskId = p->array[BUSMAIL_OFFSET_MAIL_TASK_ID];
5795               MsgProgId = p->array[BUSMAIL_OFFSET_MAIL_PROGRAM_ID];
5796               MsgPrimitiveLSB = p->array[BUSMAIL_OFFSET_MAIL_PRIMITIVE_LSB];
5797               MsgPrimitiveMSB = p->array[BUSMAIL_OFFSET_MAIL_PRIMITIVE_MSB];
5798               MsgPrimitive = MsgPrimitiveMSB << 8 | MsgPrimitiveLSB;
5799 
5800               if (option_debug > 1)
5801                 DEBUGA_CVM
5802                   ("BUSMAIL_HEADER_INFO_FRAME ProgId %X, TaskId %X, Primitive %X %X\n",
5803                    CELLIAX_P_LOG, MsgProgId, MsgTaskId, MsgPrimitiveMSB, MsgPrimitiveLSB);
5804 
5805               switch (MsgPrimitive) {
5806 
5807               case API_PP_ACCESS_RIGHTS_REJ:
5808                 /* FP rejected our registration... */
5809                 WARNINGA("API_PP_ACCESS_RIGHTS_REJ, FP rejected our registration...\n",
5810                          CELLIAX_P_LOG);
5811 
5812                 p->cvm_register_state = CVM_UNREGISTERED_TO_FP;
5813                 p->cvm_lock_state = CVM_UNKNOWN_LOCK_STATE;
5814                 known = 1;
5815                 break;
5816 
5817               case API_PP_ACCESS_RIGHTS_CFM:
5818                 /* FP accepted our registration... */
5819                 if (option_debug > 1)
5820                   DEBUGA_CVM
5821                     ("API_PP_ACCESS_RIGHTS_CFM, FP accepted our registration...\n",
5822                      CELLIAX_P_LOG);
5823 
5824                 p->cvm_register_state = CVM_REGISTERED_TO_FP;
5825                 p->cvm_lock_state = CVM_UNKNOWN_LOCK_STATE;
5826                 p->cvm_handset_no = p->array[BUSMAIL_OFFSET_MAIL_PARAMS + 0];
5827                 p->cvm_fp_is_cvm = p->array[BUSMAIL_OFFSET_MAIL_PARAMS + 1];
5828 
5829                 if (option_debug > 1)
5830                   DEBUGA_CVM
5831                     ("API_PP_ACCESS_RIGHTS_CFM, FP accepted our registration, Our handset no. is %d, CVM? %X\n",
5832                      CELLIAX_P_LOG, p->cvm_handset_no, p->cvm_fp_is_cvm);
5833 
5834                 known = 1;
5835                 break;
5836 
5837               case API_PP_LOCKED_IND:
5838                 /* CVM is connected to FP */
5839                 if (option_debug > 1)
5840                   DEBUGA_CVM("API_PP_LOCKED_IND, Connection to FP completed...\n",
5841                              CELLIAX_P_LOG);
5842 
5843                 p->cvm_register_state = CVM_REGISTERED_TO_FP;
5844                 p->cvm_lock_state = CVM_LOCKED_TO_FP;
5845                 known = 1;
5846                 break;
5847 
5848               case API_PP_UNLOCKED_IND:
5849                 /* CVM is unlocked with FP, Out of service */
5850                 WARNINGA
5851                   ("API_PP_UNLOCKED_IND, CVM is unlocked with FP, Out of service !!!\n",
5852                    CELLIAX_P_LOG);
5853 
5854                 p->cvm_lock_state = CVM_UNLOCKED_TO_FP;
5855                 known = 1;
5856                 break;
5857 
5858               case API_PP_SETUP_ACK_IND:
5859                 /* Outgoing call, connection to FP established, FP is waiting for a number to dial */
5860                 if (option_debug > 1)
5861                   DEBUGA_CVM
5862                     ("API_PP_SETUP_ACK_IND, connection to FP established, FP is waiting for a numer to dial...\n",
5863                      CELLIAX_P_LOG);
5864 
5865                 if (AST_STATE_DOWN == p->interface_state) {
5866                   p->interface_state = AST_STATE_DIALING;
5867                 }
5868 
5869                 known = 1;
5870                 break;
5871 
5872               case API_PP_ALERT_IND:
5873                 /* Outgoing call, Remote end is ringing */
5874                 if (option_debug > 1)
5875                   DEBUGA_CVM("API_PP_ALERT_IND, remote end is ringing...\n",
5876                              CELLIAX_P_LOG);
5877 
5878                 if (AST_STATE_DIALING == p->interface_state) {
5879                   p->interface_state = AST_STATE_RINGING;
5880                 }
5881 
5882                 known = 1;
5883                 break;
5884 
5885               case API_PP_CONNECT_IND:
5886                 /* Outgoing call, the remote end answered our call */
5887                 if (option_debug > 1)
5888                   DEBUGA_CVM("API_PP_CONNECT_IND, our call was answered...\n",
5889                              CELLIAX_P_LOG);
5890 
5891                 if (AST_STATE_RINGING == p->interface_state) {
5892 
5893                   /* let's open audio and have a chat */
5894                   celliax_serial_send_info_frame_CVM_BUSMAIL(p, CVM_PP_AUDIO_OPEN_REQ, 0,
5895                                                              NULL);
5896 
5897                   unsigned char volume = (unsigned char) p->cvm_volume_level;
5898                   celliax_serial_send_info_frame_CVM_BUSMAIL(p,
5899                                                              CVM_PP_AUDIO_SET_VOLUME_REQ,
5900                                                              sizeof(volume), &volume);
5901 
5902                   /* let's unmute mic and have a chat */
5903                   celliax_serial_send_info_frame_CVM_BUSMAIL(p,
5904                                                              CVM_PP_AUDIO_UNMUTE_MIC_REQ,
5905                                                              0, NULL);
5906 
5907                   /* let's switch to headset, because we fried normal output.... */
5908 /*                  unsigned char headset_on = (unsigned char) 1;
5909                   celliax_serial_send_info_frame_CVM_BUSMAIL(p, CVM_PP_AUDIO_HS_PLUG_IND, sizeof(headset_on), &headset_on);
5910 */
5911                   p->interface_state = AST_STATE_UP;
5912                   ast_setstate(p->owner, AST_STATE_RINGING);
5913                   celliax_queue_control(p->owner, AST_CONTROL_ANSWER);
5914                 }
5915 
5916                 known = 1;
5917                 break;
5918 
5919               case API_PP_REJECT_IND:
5920                 /* Outgoing/Incoming call, FP rejected our connection... */
5921                 if (option_debug > 1)
5922                   DEBUGA_CVM
5923                     ("API_PP_REJECT_IND, FP or ther PP rejected our connection...\n",
5924                      CELLIAX_P_LOG);
5925 
5926                 if (AST_STATE_RING == p->interface_state && p->owner) {
5927                   /* Attempt to answer incoming call rejected by FP or PP */
5928                   if (option_debug > 1)
5929                     DEBUGA_CVM("Was it PAGE_ALL CALL, that we should not answered?\n",
5930                                CELLIAX_P_LOG);
5931 
5932                   p->interface_state = AST_STATE_DOWN;
5933                   celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
5934 
5935                 } else if (AST_STATE_DOWN != p->interface_state && p->owner) {
5936                   /* Outgoing call rejected by other PP or FP */
5937                   p->interface_state = AST_STATE_BUSY;
5938                   ast_setstate(p->owner, AST_STATE_BUSY);
5939                   celliax_queue_control(p->owner, AST_CONTROL_BUSY);
5940                 }
5941 
5942                 known = 1;
5943                 break;
5944 
5945               case API_PP_SIGNAL_ON_IND:
5946                 /* Ringback, ignore it... */
5947                 if (option_debug > 1)
5948                   DEBUGA_CVM("API_PP_SIGNAL_ON_IND, Ringback, ignore it...\n",
5949                              CELLIAX_P_LOG);
5950 
5951                 known = 1;
5952                 break;
5953 
5954               case API_PP_SIGNAL_OFF_IND:
5955                 /* Ringback, ignore it... */
5956                 if (option_debug > 1)
5957                   DEBUGA_CVM("API_PP_SIGNAL_OFF_IND, Ringback, ignore it...\n",
5958                              CELLIAX_P_LOG);
5959 
5960                 known = 1;
5961                 break;
5962 
5963               case API_PP_SETUP_IND:
5964                 /* Incoming call, Somebody is calling us */
5965 
5966                 if (option_debug > 1)
5967                   DEBUGA_CVM("API_PP_SETUP_IND, somebody is calling us...\n",
5968                              CELLIAX_P_LOG);
5969 
5970                 if (AST_STATE_DOWN == p->interface_state) {
5971 
5972                   if (API_PP_SETUP_IND_CALL_INT ==
5973                       p->array[BUSMAIL_OFFSET_MAIL_PARAMS +
5974                                API_PP_SETUP_IND_CALL_TYPE_OFFSET]) {
5975                     DEBUGA_CVM("INTERNAL CALL, receive it...\n", CELLIAX_P_LOG);
5976 
5977                     p->interface_state = AST_STATE_RING;
5978 
5979                     /* inform calling end, that we know about his call, and that we are alerting */
5980                     celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_ALERT_REQ, 0,
5981                                                                NULL);
5982 
5983                     /* let's open audio before valid mac, to remove noise... */
5984                     celliax_serial_send_info_frame_CVM_BUSMAIL(p,
5985                                                                CVM_PP_AUDIO_OPEN_ADPCM_OFF_REQ,
5986                                                                0, NULL);
5987 
5988                   } else {
5989                     DEBUGA_CVM("NOT an INTERNAL CALL, CALL TYPE %X, just ignore it...\n",
5990                                CELLIAX_P_LOG,
5991                                p->array[BUSMAIL_OFFSET_MAIL_PARAMS +
5992                                         API_PP_SETUP_IND_CALL_TYPE_OFFSET]);
5993 
5994                     /* inform calling end, that we know about his call, and that we are alerting OR not :) */
5995                     /* probably it is needed so FP does not remove us from PP list :) */
5996                     celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_ALERT_REQ, 0,
5997                                                                NULL);
5998                   }
5999 
6000                 } else {
6001                   WARNINGA
6002                     ("Ignore incoming call, Wrong interface state, current state %X\n",
6003                      CELLIAX_P_LOG, p->interface_state);
6004                 }
6005 
6006                 known = 1;
6007                 break;
6008 
6009               case API_PP_ALERT_OFF_IND:
6010                 /* Incoming call, We should stop alerting about incoming call... */
6011                 if (option_debug > 1)
6012                   DEBUGA_CVM
6013                     ("API_PP_ALERT_OFF_IND, Ringback, stop alerting about incoming call...\n",
6014                      CELLIAX_P_LOG);
6015 
6016                 known = 1;
6017                 break;
6018 
6019               case API_PP_ALERT_ON_IND:
6020                 /* Incoming call, We should stop alerting about incoming call... */
6021                 if (option_debug > 1)
6022                   DEBUGA_CVM
6023                     ("API_PP_ALERT_ON_IND, Ringback, start alerting about incoming call...\n",
6024                      CELLIAX_P_LOG);
6025 /*
6026                 if (AST_STATE_DOWN == p->interface_state) {
6027                   DEBUGA_CVM("Somebody is calling us, we see a PP_ALERT_ON_IND, receive it...\n", CELLIAX_P_LOG);
6028                   p->interface_state = AST_STATE_RING;
6029                 }
6030 */
6031                 known = 1;
6032                 break;
6033 
6034               case API_PP_CONNECT_CFM:
6035                 /* Incoming call, Confirmation for request to answer incoming call... */
6036                 if (option_debug > 1)
6037                   DEBUGA_CVM
6038                     ("API_PP_CONNECT_CFM, Confirmation for request to answer incoming call...\n",
6039                      CELLIAX_P_LOG);
6040 
6041                 if (AST_STATE_RING == p->interface_state && p->owner) {
6042 
6043                   p->interface_state = AST_STATE_UP;
6044                   ast_setstate(p->owner, AST_STATE_UP);
6045 
6046                   /* let's open audio and have a chat */
6047 //                  celliax_serial_send_info_frame_CVM_BUSMAIL(p, CVM_PP_AUDIO_OPEN_ADPCM_OFF_REQ, 0, NULL);
6048 
6049                   /* let's open audio and have a chat */
6050                   celliax_serial_send_info_frame_CVM_BUSMAIL(p, CVM_PP_AUDIO_OPEN_REQ, 0,
6051                                                              NULL);
6052 
6053                   unsigned char volume = (unsigned char) p->cvm_volume_level;
6054                   celliax_serial_send_info_frame_CVM_BUSMAIL(p,
6055                                                              CVM_PP_AUDIO_SET_VOLUME_REQ,
6056                                                              sizeof(volume), &volume);
6057 
6058                   /* let's unmute mic and have a chat */
6059                   celliax_serial_send_info_frame_CVM_BUSMAIL(p,
6060                                                              CVM_PP_AUDIO_UNMUTE_MIC_REQ,
6061                                                              0, NULL);
6062 
6063                   /* let's switch to headset, because we fried normal output.... */
6064 /*                  unsigned char headset_on = (unsigned char) 1;
6065                   celliax_serial_send_info_frame_CVM_BUSMAIL(p, CVM_PP_AUDIO_HS_PLUG_IND, sizeof(headset_on), &headset_on);
6066 */
6067                 } else {
6068                   WARNINGA
6069                     ("Ignore connection cfm, Wrong interface state, current state %X\n",
6070                      CELLIAX_P_LOG, p->interface_state);
6071                 }
6072 
6073                 known = 1;
6074                 break;
6075 
6076               case API_PP_RELEASE_CFM:
6077                 /* Confirmation for request to hangup a call... */
6078                 if (option_debug > 1)
6079                   DEBUGA_CVM
6080                     ("API_PP_RELEASE_CFM, Confirmation for request to hangup a call..\n",
6081                      CELLIAX_P_LOG);
6082 
6083                 if (AST_STATE_UP == p->interface_state) {
6084                   /* let's close audio */
6085                   celliax_serial_send_info_frame_CVM_BUSMAIL(p, CVM_PP_AUDIO_CLOSE_REQ, 0,
6086                                                              NULL);
6087 
6088                   /* let's unmute mic and have a chat */
6089                   celliax_serial_send_info_frame_CVM_BUSMAIL(p, CVM_PP_AUDIO_MUTE_MIC_REQ,
6090                                                              0, NULL);
6091                 }
6092 
6093                 p->interface_state = AST_STATE_DOWN;
6094 
6095                 known = 1;
6096                 break;
6097 
6098               case API_PP_RELEASE_IND:
6099                 /* FP releases connection to CVM... */
6100                 if (option_debug > 1)
6101                   DEBUGA_CVM("API_PP_RELEASE_IND, FP releases connection to CVM...\n",
6102                              CELLIAX_P_LOG);
6103 
6104                 if (AST_STATE_UP == p->interface_state && p->owner) {
6105                   /* let's close audio */
6106                   celliax_serial_send_info_frame_CVM_BUSMAIL(p, CVM_PP_AUDIO_CLOSE_REQ, 0,
6107                                                              NULL);
6108                   p->interface_state = AST_STATE_DOWN;
6109                   celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
6110 
6111                 } else if (AST_STATE_RING == p->interface_state && p->owner) {
6112                   /* workaround for PAGE ALL CALL, FIXME!!!! */
6113                   if (option_debug > 1)
6114                     DEBUGA_CVM("WAS IT A PAGE ALL ???...\n", CELLIAX_P_LOG);
6115 
6116                   p->interface_state = AST_STATE_UP;
6117                   usleep(100000);
6118 
6119                   p->interface_state = AST_STATE_DOWN;
6120                   celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
6121                 }
6122 
6123                 /* we need to ACK release */
6124                 celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_RELEASE_RES, 0,
6125                                                            NULL);
6126 
6127                 known = 1;
6128                 break;
6129 
6130               case API_PP_READ_RSSI_CFM:
6131                 if (option_debug > 1)
6132                   DEBUGA_CVM("API_PP_READ_RSSI_CFM, RSSI readout...\n", CELLIAX_P_LOG);
6133 
6134                 p->cvm_rssi = p->array[BUSMAIL_OFFSET_MAIL_PARAMS + 0];
6135                 int rssi_percent = p->cvm_rssi * 100 / 0x3F;
6136                 if (option_debug > 1)
6137                   DEBUGA_CVM("RSSI is %X, %d%%...\n", CELLIAX_P_LOG, p->cvm_rssi,
6138                              rssi_percent);
6139 
6140                 known = 1;
6141                 break;
6142               default:
6143                 WARNINGA("UNKNOWN MsgPrimitive!!! %X\n", CELLIAX_P_LOG, MsgPrimitive);
6144                 break;
6145               }
6146 
6147               break;
6148 
6149             case BUSMAIL_HEADER_CTRL_FRAME:
6150               if (option_debug > 1)
6151                 DEBUGA_CVM("BUSMAIL_HEADER_CTRL_FRAME\n", CELLIAX_P_LOG);
6152 
6153               switch (p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_SU_BIT_MASK) {
6154               case BUSMAIL_HEADER_CTRL_SU_FRAME:
6155                 if (option_debug > 1)
6156                   DEBUGA_CVM("BUSMAIL_HEADER_CTRL_SU_FRAME\n", CELLIAX_P_LOG);
6157 
6158                 switch (p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_SUID_MASK) {
6159                 case BUSMAIL_HEADER_SUID_REJ:
6160                   /* CVM Reject, CVM missed one of our packets, it will be resend, do nothing */
6161                   MsgRxSeqNo =
6162                     ((p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_RXSEQ_MASK));
6163 
6164                   if (option_debug > 1)
6165                     DEBUGA_CVM("BUSMAIL_HEADER_SUID_REJ, RxSeq %X\n", CELLIAX_P_LOG,
6166                                MsgRxSeqNo);
6167 
6168                   /* Even that it is CVM Reject packet, it still ACKs some packets */
6169                   celliax_serial_list_acknowledge_CVM_BUSMAIL(p, MsgRxSeqNo);
6170 
6171                   known = 1;
6172                   break;
6173                 case BUSMAIL_HEADER_SUID_RNR:
6174                   /* CVM Receiver Not Ready, answer to packet that we sent, do nothing, it will be resend later */
6175                   MsgRxSeqNo =
6176                     ((p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_RXSEQ_MASK));
6177 
6178                   if (option_debug > 1)
6179                     DEBUGA_CVM("BUSMAIL_HEADER_SUID_RNR, RxSeq %X\n", CELLIAX_P_LOG,
6180                                MsgRxSeqNo);
6181 
6182                   known = 1;
6183                   break;
6184                 case BUSMAIL_HEADER_SUID_RR:
6185                   /* CVM ACKs our packets */
6186                   MsgRxSeqNo =
6187                     ((p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_RXSEQ_MASK));
6188 
6189                   if (option_debug > 1)
6190                     DEBUGA_CVM("BUSMAIL_HEADER_SUID_RR, RxSeq %X\n", CELLIAX_P_LOG,
6191                                MsgRxSeqNo);
6192 
6193                   /* CVM ACKed our frames with RR frame */
6194                   celliax_serial_list_acknowledge_CVM_BUSMAIL(p, MsgRxSeqNo);
6195 
6196                   known = 1;
6197                   break;
6198 
6199                 default:
6200                   WARNINGA("BUSMAIL_HEADER_SUID_UNKNOWN!!!\n", CELLIAX_P_LOG);
6201                   break;
6202                 }
6203                 break;
6204 
6205               case BUSMAIL_HEADER_CTRL_UN_FRAME:
6206                 if (option_debug > 1)
6207                   DEBUGA_CVM("BUSMAIL_HEADER_CTRL_UN_FRAME\n", CELLIAX_P_LOG);
6208 
6209                 switch (p->array[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_UNID_MASK) {
6210 
6211                 case BUSMAIL_HEADER_UNID_SABM:
6212                   if (option_debug > 1)
6213                     DEBUGA_CVM("BUSMAIL_HEADER_UNID_SABM\n", CELLIAX_P_LOG);
6214                   /* reset seq counters */
6215                   p->busmail_txseq_celliax_last = 0xFF;
6216                   p->busmail_rxseq_cvm_last = 0xFF;
6217 
6218                   celliax_serial_lists_free_CVM_BUSMAIL(p);
6219                   /* if needed, reply will be send by code at the end of switch statements */
6220                   known = 1;
6221                   break;
6222 
6223                 default:
6224                   WARNINGA("BUSMAIL_HEADER_UNID_UNKNOWN!!!\n", CELLIAX_P_LOG);
6225                   break;
6226                 }
6227                 break;
6228 
6229               default:
6230                 WARNINGA("BUSMAIL_HEADER_CTRL_UNKNOWN!!!\n", CELLIAX_P_LOG);
6231                 break;
6232               }
6233               break;
6234 
6235             default:
6236               WARNINGA("BUSMAIL_HEADER_UNKNOWN!!!\n", CELLIAX_P_LOG);
6237               break;
6238             }
6239 
6240           }
6241 
6242           /* categorization of frame is ended, if it has not been recognized, whine */
6243           if (!known) {
6244             WARNINGA("BUSMAIL MSG UNKNOWN or REJECTED!\n", CELLIAX_P_LOG);
6245           }
6246         }
6247         p->arraycounter++;
6248       }
6249     }
6250     CVM_UNLOCKA(&p->controldev_lock);
6251     POPPA_UNLOCKA(&p->controldev_lock);
6252   }
6253 
6254   /* oooops, select returned error, got a kill/cancel or problems with the serial file descriptor */
6255   if (select_err == -1) {
6256     if (errno != EINTR) {
6257       ERRORA
6258         ("select returned -1 on %s, marking controldev as dead, errno was: %d, error was: %s\n",
6259          CELLIAX_P_LOG, p->controldevice_name, errno, strerror(errno));
6260 
6261       p->controldev_dead = 1;
6262       close(p->controldevfd);
6263 
6264       if (p->owner)
6265         celliax_queue_control(p->owner, AST_CONTROL_HANGUP);
6266       return -1;
6267 
6268     } else {
6269       WARNINGA("select returned -1 on %s, errno was: %d, EINTR, error was: %s\n",
6270                CELLIAX_P_LOG, p->controldevice_name, errno, strerror(errno));
6271       return 0;
6272     }
6273   }
6274   /* OK, reading done, let's browse the list of pending frames to be sent, and act on it */
6275   if (celliax_serial_send_if_time_CVM_BUSMAIL(p)) {
6276     ERRORA("celliax_serial_send_if_time_CVM_BUSMAIL failed!\n", CELLIAX_P_LOG);
6277     return -1;
6278   }
6279 
6280   return cvm_busmail_mesg;      //FIXME breaks the convention of returning 0 on success
6281 }
6282 
celliax_serial_getstatus_CVM_BUSMAIL(struct celliax_pvt * p)6283 int celliax_serial_getstatus_CVM_BUSMAIL(struct celliax_pvt *p)
6284 {
6285   int res;
6286   int how_many_reads = 0;
6287 
6288   PUSHA_UNLOCKA(&p->controldev_lock);
6289   CVM_LOKKA(&p->controldev_lock);
6290 
6291   if (option_debug > 1)
6292     DEBUGA_CVM("Sending RR CTRL frame wit PF bit set\n", CELLIAX_P_LOG);
6293 
6294   /* this ctrl frame can be used as low level keep alive */
6295   celliax_serial_send_ctrl_frame_CVM_BUSMAIL(p,
6296                                              BUSMAIL_HEADER_CTRL_FRAME |
6297                                              BUSMAIL_HEADER_CTRL_SU_FRAME |
6298                                              BUSMAIL_HEADER_SUID_RR |
6299                                              (BUSMAIL_HEADER_PF_BIT_MASK & 0xFF));
6300 
6301   //usleep(1000);
6302 
6303   res = celliax_serial_read_CVM_BUSMAIL(p); //we don't have no monitor neither do_controldev_thread
6304 
6305   if (res == -1) {
6306     ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
6307     CVM_UNLOCKA(&p->controldev_lock);
6308     return -1;
6309   }
6310 
6311   while ((res & 0xF0) !=
6312          (BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_SU_FRAME |
6313           BUSMAIL_HEADER_SUID_RR)) {
6314 
6315     usleep(1000);
6316     res = celliax_serial_read_CVM_BUSMAIL(p);
6317     how_many_reads++;
6318 
6319     if (res == -1) {
6320       ERRORA("failed celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG);
6321       CVM_UNLOCKA(&p->controldev_lock);
6322       return -1;
6323     }
6324 
6325     if (how_many_reads > 10) {
6326       ERRORA("no expected results in %d celliax_serial_read_CVM_BUSMAIL\n", CELLIAX_P_LOG,
6327              how_many_reads);
6328       CVM_UNLOCKA(&p->controldev_lock);
6329       return -1;
6330     }
6331   }
6332 
6333   //celliax_serial_send_info_frame_CVM_BUSMAIL(p, API_PP_READ_RSSI_REQ, 0, NULL);
6334 
6335   CVM_UNLOCKA(&p->controldev_lock);
6336   POPPA_UNLOCKA(&p->controldev_lock);
6337 
6338   return 0;
6339 
6340 }
6341 
6342 /*!
6343  * \brief Write on the serial port for all the CVM_BUSMAIL functions
6344  * \param p celliax_pvt
6345  * \param len lenght of buffer2
6346  * \param buffer2 chars to be written
6347  *
6348  * Write on the serial port for all the CVM_BUSMAIL functions
6349  *
6350  * \return the number of chars written on the serial,
6351  * that can be different from len (or negative) in case of errors.
6352  */
celliax_serial_send_CVM_BUSMAIL(struct celliax_pvt * p,int len,unsigned char * mesg_ptr)6353 int celliax_serial_send_CVM_BUSMAIL(struct celliax_pvt *p, int len,
6354                                     unsigned char *mesg_ptr)
6355 {
6356   int ret;
6357   size_t actual = 0;
6358   unsigned char *mesg_ptr2 = mesg_ptr;
6359   PUSHA_UNLOCKA(&p->controldev_lock);
6360   CVM_LOKKA(&p->controldev_lock);
6361   do {
6362     ret = write(p->controldevfd, mesg_ptr, len - actual);
6363     if (ret < 0 && errno == EAGAIN)
6364       continue;
6365     if (ret < 0) {
6366       if (actual != len)
6367         ERRORA("celliax_serial_write error: %s", CELLIAX_P_LOG, strerror(errno));
6368       CVM_UNLOCKA(&p->controldev_lock);
6369       return -1;
6370     }
6371     actual += ret;
6372     mesg_ptr += ret;
6373     usleep(10000);
6374 //    usleep(p->cvm_celliax_serial_delay*1000);
6375   } while (actual < len);
6376 
6377   usleep(p->cvm_celliax_serial_delay * 1000);
6378 
6379 //  tcdrain(p->controldevfd);
6380 
6381   CVM_UNLOCKA(&p->controldev_lock);
6382   POPPA_UNLOCKA(&p->controldev_lock);
6383 
6384   if (option_debug > 10) {
6385     int i;
6386     char debug_buf[1024];
6387     char *debug_buf_pos;
6388 
6389     memset(debug_buf, 0, 1024);
6390     debug_buf_pos = debug_buf;
6391 
6392     for (i = 0; i < len; i++) {
6393       debug_buf_pos += sprintf(debug_buf_pos, "[%.2X] ", mesg_ptr2[i]);
6394       if (debug_buf_pos > ((char *) &debug_buf + 1000))
6395         break;
6396     }
6397     DEBUGA_CVM("%s was sent down the wire\n", CELLIAX_P_LOG, debug_buf);
6398   }
6399 
6400   return 0;
6401 }
6402 
6403 /*!
6404  * \brief Flags as acknowledged an BUSMAIL message previously sent
6405  * \param p celliax_pvt
6406  * \param seqnum identifier of the message to be acknowledged
6407  *
6408  * Called upon receiving an BUSMAIL acknoledgement message, browse the cvm_busmail_outgoing_list
6409  * looking for the seqnum sent BUSMAIL message, and flags it as acknowledged.
6410  * (if an outgoing BUSMAIL message is not aknowledged by the cellphone in a while,
6411  * it will be retransmitted)
6412  *
6413  * \return 0 on error, 1 otherwise
6414  */
celliax_serial_list_acknowledge_CVM_BUSMAIL(struct celliax_pvt * p,unsigned char AckTxSeqNo)6415 int celliax_serial_list_acknowledge_CVM_BUSMAIL(struct celliax_pvt *p,
6416                                                 unsigned char AckTxSeqNo)
6417 {
6418   struct cvm_busmail_msg *ptr = NULL;
6419   struct cvm_busmail_msg *old = NULL;
6420 
6421   unsigned char MsgTxSeqNo;
6422   unsigned char MsgRxSeqNo;
6423 
6424   ptr = p->cvm_busmail_outgoing_list;
6425 
6426   if (ptr == NULL) {
6427     ERRORA("cvm_busmail_outgoing_list is NULL ?\n", CELLIAX_P_LOG);
6428     return -1;
6429   }
6430 
6431   PUSHA_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6432   CVM_LOKKA(&p->cvm_busmail_outgoing_list_lock);
6433 /*
6434   DEBUGA_CVM("PREFREE OUTGOING list:\n", CELLIAX_P_LOG);
6435   celliax_serial_list_print_CVM_BUSMAIL(p, p->cvm_busmail_outgoing_list);
6436 */
6437   while (ptr->next != NULL)
6438     ptr = ptr->next;
6439 
6440   while (ptr) {
6441 
6442     if ((1 == ptr->valid) && (0 == ptr->acknowledged) && (0 != ptr->sent)) {
6443       MsgTxSeqNo =
6444         ((ptr->busmail_msg_buffer[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_TXSEQ_MASK) >>
6445          4);
6446       MsgRxSeqNo =
6447         ((ptr->busmail_msg_buffer[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_RXSEQ_MASK));
6448 
6449 /*
6450     if (option_debug > 1)
6451       DEBUGA_CVM("OUTGOING LIST TxSeq is %X, RxSeq is %X\n", CELLIAX_P_LOG, MsgTxSeqNo, MsgRxSeqNo);
6452 */
6453       unsigned char TxToAck = 0;
6454 
6455       if (0 == AckTxSeqNo) {
6456         TxToAck = 7;
6457       } else {
6458         TxToAck = AckTxSeqNo - 1;
6459       }
6460 
6461       if (MsgTxSeqNo <= TxToAck) {
6462 
6463         if (option_debug > 1)
6464           DEBUGA_CVM("Msg with TxSeq=%X ACKed with CvmRxSeq=%X\n", CELLIAX_P_LOG,
6465                      MsgTxSeqNo, AckTxSeqNo);
6466 
6467         old = ptr;
6468         old->acknowledged = 1;
6469         old->valid = 0;
6470         ptr = old->previous;
6471 
6472         if (old->previous) {
6473           if (old->next) {
6474             old->previous->next = old->next;
6475           } else {
6476             old->previous->next = NULL;
6477           }
6478         }
6479 
6480         if (old->next) {
6481           if (old->previous) {
6482             old->next->previous = old->previous;
6483           } else {
6484             old->next->previous = NULL;
6485           }
6486         }
6487 
6488         if ((NULL == old->next) && (NULL == old->previous)) {
6489           if (option_debug > 1) {
6490             DEBUGA_CVM("FREEING LAST\n", CELLIAX_P_LOG);
6491           }
6492 
6493           p->cvm_busmail_outgoing_list = NULL;
6494           p->cvm_busmail_outgoing_list = celliax_serial_list_init_CVM_BUSMAIL(p);
6495         }
6496 
6497 /*
6498       if (option_debug > 1)
6499         DEBUGA_CVM("FREEING TxSeq is %X, RxSeq is %X\n", CELLIAX_P_LOG, MsgTxSeqNo, MsgRxSeqNo);
6500 */
6501 
6502         free(old);
6503 
6504       } else {
6505         ptr = ptr->previous;
6506       }
6507 
6508     } else {
6509       ptr = ptr->previous;
6510     }
6511   }
6512 
6513 /*
6514   DEBUGA_CVM("POSTFREE OUTGOING list:\n", CELLIAX_P_LOG);
6515   celliax_serial_list_print_CVM_BUSMAIL(p, p->cvm_busmail_outgoing_list);
6516 */
6517 
6518   CVM_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6519   POPPA_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6520   return 0;
6521 }
6522 
6523 /*!
6524  * \brief Sends an FBUS2 message or resends it if it was not acknowledged
6525  * \param p celliax_pvt
6526  *
6527  * Called by celliax_serial_read_CVM_BUSMAIL, browse the fbus2_outgoing_list looking for FBUS2 messages to be sent,
6528  * or for FBUS2 messages previously sent but not yet acknoledged.
6529  * (if an outgoing FBUS2 message is not aknowledged by the cellphone in a while,
6530  * it will be retransmitted)
6531  *
6532  * \return 0 on error, 1 otherwise
6533  */
celliax_serial_send_if_time_CVM_BUSMAIL(struct celliax_pvt * p)6534 int celliax_serial_send_if_time_CVM_BUSMAIL(struct celliax_pvt *p)
6535 {
6536   struct cvm_busmail_msg *ptr;
6537   struct timeval tv;
6538   struct timezone tz;
6539 
6540   gettimeofday(&tv, &tz);
6541   ptr = p->cvm_busmail_outgoing_list;
6542 
6543   if (ptr == NULL) {
6544 /*    ERRORA("cvm_busmail_outgoing_list is NULL ?\n", CELLIAX_P_LOG); */
6545     WARNINGA("cvm_busmail_outgoing_list is NULL, nothing to send...\n", CELLIAX_P_LOG);
6546 
6547 /*    return -1; */
6548     return 0;
6549 
6550   }
6551 
6552   while (ptr->next != NULL) {
6553     WARNINGA("cvm_busmail_outgoing_list->next is not null ?\n", CELLIAX_P_LOG);
6554     ptr = ptr->next;            //FIXME what to do?
6555   }
6556 
6557   while (ptr->sent == 0 && ptr->acknowledged == 0) {
6558     if (ptr->previous != NULL) {
6559       ptr = ptr->previous;
6560     } else
6561       break;
6562   }
6563 
6564   while (ptr->sent == 1 && ptr->acknowledged == 0) {
6565     if (ptr->previous != NULL) {
6566       ptr = ptr->previous;
6567     } else
6568       break;
6569   }
6570 
6571   if (ptr->sent == 1 && ptr->acknowledged == 1) {
6572     if (ptr->next != NULL) {
6573       ptr = ptr->next;
6574     }
6575   }
6576 
6577   if (ptr->sent == 1 && ptr->acknowledged == 0 && ptr->valid == 1) {
6578     if ((tv.tv_sec * 1000 + tv.tv_usec / 1000) >
6579         ((ptr->tv_sec * 1000 + ptr->tv_usec / 1000) + 1000)) {
6580 
6581       PUSHA_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6582       CVM_LOKKA(&p->cvm_busmail_outgoing_list_lock);
6583 
6584       if (ptr->sent == 1 && ptr->acknowledged == 0 && ptr->valid == 1) {    //retest, maybe has been changed?
6585         if ((tv.tv_sec * 1000 + tv.tv_usec / 1000) > ((ptr->tv_sec * 1000 + ptr->tv_usec / 1000) + 1000)) { //retest, maybe has been changed?
6586 
6587           if (option_debug > 1)
6588             DEBUGA_CVM("RESEND TxSeq=%X, passed %ld ms, sent %d times\n", CELLIAX_P_LOG,
6589                        ptr->txseqno,
6590                        ((tv.tv_sec * 1000 + tv.tv_usec / 1000) -
6591                         (ptr->tv_sec * 1000 + ptr->tv_usec / 1000)), ptr->how_many_sent);
6592 
6593           if (ptr->how_many_sent > 9) {
6594             ERRORA("RESEND TxSeq=%X, passed %ld ms, sent %d times\n", CELLIAX_P_LOG,
6595                    ptr->txseqno,
6596                    ((tv.tv_sec * 1000 + tv.tv_usec / 1000) -
6597                     (ptr->tv_sec * 1000 + ptr->tv_usec / 1000)), ptr->how_many_sent);
6598 
6599             CVM_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6600             return -1;
6601           }
6602 
6603           celliax_serial_send_CVM_BUSMAIL(p, ptr->busmail_msg_len,
6604                                           ptr->busmail_msg_buffer);
6605 
6606           ptr->tv_sec = tv.tv_sec;
6607           ptr->tv_usec = tv.tv_usec;
6608           ptr->sent = 1;
6609           ptr->how_many_sent++;
6610 /*
6611           if (option_debug > 1) {
6612             DEBUGA_CVM("OUTGOING list:\n", CELLIAX_P_LOG);
6613             celliax_serial_list_print_CVM_BUSMAIL(p, p->cvm_busmail_outgoing_list);
6614             DEBUGA_CVM("OUTGOING list END\n", CELLIAX_P_LOG);
6615           }
6616 */
6617         }
6618       }
6619 
6620       CVM_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6621       POPPA_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6622     }
6623   }
6624 
6625   if (ptr->sent == 0 && ptr->acknowledged == 0 && ptr->valid == 1) {
6626 
6627     PUSHA_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6628     CVM_LOKKA(&p->cvm_busmail_outgoing_list_lock);
6629 
6630     if (ptr->sent == 0 && ptr->acknowledged == 0 && ptr->valid == 1) {  //retest, maybe has been changed?
6631 
6632       if (option_debug > 1)
6633         DEBUGA_CVM("SENDING 1st TIME TxSeq=%X\n", CELLIAX_P_LOG, ptr->txseqno);
6634 
6635       celliax_serial_send_CVM_BUSMAIL(p, ptr->busmail_msg_len, ptr->busmail_msg_buffer);
6636 
6637       ptr->tv_sec = tv.tv_sec;
6638       ptr->tv_usec = tv.tv_usec;
6639       ptr->sent = 1;
6640       ptr->how_many_sent++;
6641 /*
6642       if (option_debug > 1) {
6643         DEBUGA_CVM("OUTGOING list:\n", CELLIAX_P_LOG);
6644         celliax_serial_list_print_CVM_BUSMAIL(p, p->cvm_busmail_outgoing_list);
6645         DEBUGA_CVM("OUTGOING list END\n", CELLIAX_P_LOG);
6646       }
6647 */
6648     }
6649 
6650     CVM_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6651     POPPA_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6652 
6653   }
6654   return 0;
6655 }
6656 
celliax_serial_write_CVM_BUSMAIL(struct celliax_pvt * p,struct cvm_busmail_frame * busmail_frame)6657 int celliax_serial_write_CVM_BUSMAIL(struct celliax_pvt *p,
6658                                      struct cvm_busmail_frame *busmail_frame)
6659 {
6660   unsigned char buffer2[BUSMAIL_MAX_FRAME_LENGTH];
6661   int i = 0;
6662   int len = 0;
6663   unsigned int busmail_len_total = 0;
6664 
6665   busmail_frame->busmail_sof = BUSMAIL_SOF;
6666   busmail_frame->busmail_crc = 0;
6667 
6668 /* because of Rx Tx SEQ HEADER fields problem, update when these fields are filled with correct data
6669   busmail_frame->busmail_crc = (unsigned char)(busmail_frame->busmail_header + busmail_frame->busmail_crc);
6670 */
6671 
6672   buffer2[BUSMAIL_OFFSET_SOF] = busmail_frame->busmail_sof;
6673   buffer2[BUSMAIL_OFFSET_HEADER] = busmail_frame->busmail_header;
6674 
6675   if ((buffer2[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_IC_BIT_MASK) ==
6676       BUSMAIL_HEADER_INFO_FRAME) {
6677     len =
6678       BUSMAIL_OFFSET_MAIL_PARAMS + busmail_frame->busmail_mail_params_buffer_len +
6679       sizeof(busmail_frame->busmail_crc);
6680     busmail_len_total =
6681       busmail_frame->busmail_mail_params_buffer_len +
6682       sizeof(busmail_frame->busmail_header)
6683       + sizeof(busmail_frame->busmail_mail_program_id) +
6684       sizeof(busmail_frame->busmail_mail_task_id) + 2;
6685 
6686     if (option_debug > 1)
6687       DEBUGA_CVM("INFO frame to send\n", CELLIAX_P_LOG);
6688 
6689     buffer2[BUSMAIL_OFFSET_MAIL_PROGRAM_ID] = busmail_frame->busmail_mail_program_id;
6690     buffer2[BUSMAIL_OFFSET_MAIL_TASK_ID] = busmail_frame->busmail_mail_task_id;
6691     buffer2[BUSMAIL_OFFSET_MAIL_PRIMITIVE_LSB] =
6692       busmail_frame->busmail_mail_primitive[BUSMAIL_MAIL_PRIMITIVE_LSB];
6693     buffer2[BUSMAIL_OFFSET_MAIL_PRIMITIVE_MSB] =
6694       busmail_frame->busmail_mail_primitive[BUSMAIL_MAIL_PRIMITIVE_MSB];
6695 
6696     if (busmail_frame->busmail_mail_params_buffer_len) {
6697       memcpy(buffer2 + BUSMAIL_OFFSET_MAIL_PARAMS,
6698              busmail_frame->busmail_mail_params_buffer,
6699              busmail_frame->busmail_mail_params_buffer_len);
6700     }
6701 
6702     for (i = 0; i < busmail_frame->busmail_mail_params_buffer_len; i++) {
6703       busmail_frame->busmail_crc =
6704         (unsigned char) (busmail_frame->busmail_mail_params_buffer[i] +
6705                          busmail_frame->busmail_crc);
6706     }
6707 
6708     busmail_frame->busmail_crc += busmail_frame->busmail_mail_program_id;
6709     busmail_frame->busmail_crc += busmail_frame->busmail_mail_task_id;
6710     busmail_frame->busmail_crc +=
6711       busmail_frame->busmail_mail_primitive[BUSMAIL_MAIL_PRIMITIVE_LSB];
6712     busmail_frame->busmail_crc +=
6713       busmail_frame->busmail_mail_primitive[BUSMAIL_MAIL_PRIMITIVE_MSB];
6714   } else {
6715     busmail_len_total = sizeof(busmail_frame->busmail_header);
6716     len = BUSMAIL_OFFSET_MAIL + sizeof(busmail_frame->busmail_crc);
6717 
6718     if (option_debug > 1)
6719       DEBUGA_CVM("CTRL frame to send\n", CELLIAX_P_LOG);
6720   }
6721 
6722 /*
6723   DEBUGA_CVM("Its len=%d\n", CELLIAX_P_LOG, len);
6724 */
6725 
6726   busmail_frame->busmail_len[BUSMAIL_LEN_LSB] =
6727     (unsigned char) (busmail_len_total & 0xFF);
6728   busmail_frame->busmail_len[BUSMAIL_LEN_MSB] = (unsigned char) (busmail_len_total >> 8);
6729   buffer2[BUSMAIL_OFFSET_LEN_MSB] = busmail_frame->busmail_len[BUSMAIL_LEN_MSB];
6730   buffer2[BUSMAIL_OFFSET_LEN_LSB] = busmail_frame->busmail_len[BUSMAIL_LEN_LSB];
6731 
6732 /*
6733   buffer2[len-1] = busmail_frame->busmail_crc;
6734 */
6735   buffer2[len - 1] = 0xFF;
6736 
6737   if ((buffer2[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_IC_BIT_MASK) ==
6738       BUSMAIL_HEADER_INFO_FRAME) {
6739     /* if it is INFO frame, queue it */
6740 
6741     /* update TxSeq and RxSeq bits */
6742     /* clear TxSeq and RxSeq bits */
6743     buffer2[BUSMAIL_OFFSET_HEADER] &=
6744       ~(BUSMAIL_HEADER_RXSEQ_MASK | BUSMAIL_HEADER_TXSEQ_MASK);
6745 
6746     buffer2[BUSMAIL_OFFSET_HEADER] |=
6747       (p->busmail_rxseq_cvm_last + 1) & BUSMAIL_HEADER_RXSEQ_MASK;
6748 
6749     p->busmail_txseq_celliax_last++;
6750     p->busmail_txseq_celliax_last &= 0x07;
6751 
6752     buffer2[BUSMAIL_OFFSET_HEADER] |=
6753       ((p->busmail_txseq_celliax_last) << 4) & BUSMAIL_HEADER_TXSEQ_MASK;
6754 
6755     /* update CRC */
6756     busmail_frame->busmail_crc += buffer2[BUSMAIL_OFFSET_HEADER];
6757     buffer2[len - 1] = busmail_frame->busmail_crc;
6758 
6759     p->cvm_busmail_outgoing_list = celliax_serial_list_init_CVM_BUSMAIL(p);
6760     p->cvm_busmail_outgoing_list->busmail_msg_len = len;
6761 
6762     for (i = 0; i < len; i++) {
6763       p->cvm_busmail_outgoing_list->busmail_msg_buffer[i] = buffer2[i];
6764     }
6765 
6766     if (option_debug > 10) {
6767       char debug_buf[1024];
6768       char *debug_buf_pos;
6769 
6770       memset(debug_buf, 0, 1024);
6771       debug_buf_pos = debug_buf;
6772 
6773       for (i = 0; i < len; i++) {
6774         debug_buf_pos += sprintf(debug_buf_pos, "[%.2X] ", buffer2[i]);
6775         if (debug_buf_pos > (char *) (&debug_buf + 1000))
6776           break;
6777       }
6778 
6779       if (option_debug > 1)
6780         DEBUGA_CVM("INFO: %s was prepared to send\n", CELLIAX_P_LOG, debug_buf);
6781     }
6782 
6783     if (option_debug > 1) {
6784       DEBUGA_CVM("OUTGOING INFO Frame TxSeq is %X, RxSeq is %X\n", CELLIAX_P_LOG,
6785                  (buffer2[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_TXSEQ_MASK) >> 4,
6786                  buffer2[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_RXSEQ_MASK);
6787 /*
6788       DEBUGA_CVM("OUTGOING list:\n", CELLIAX_P_LOG);
6789       celliax_serial_list_print_CVM_BUSMAIL(p, p->cvm_busmail_outgoing_list);
6790       DEBUGA_CVM("OUTGOING list END\n", CELLIAX_P_LOG); */
6791     }
6792     p->cvm_busmail_outgoing_list->txseqno =
6793       (unsigned char) (buffer2[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_TXSEQ_MASK) >> 4;
6794     p->cvm_busmail_outgoing_list->valid = 1;    /* ready to send (?) */
6795 
6796   } else {
6797     /* if it is CTRL frame, send it straight to the wire */
6798     if (BUSMAIL_HEADER_SABM !=
6799         (buffer2[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_SABM_MASK)) {
6800       /*SABM ctrl frames have no RxSeq bits */
6801 
6802       buffer2[BUSMAIL_OFFSET_HEADER] &= ~BUSMAIL_HEADER_RXSEQ_MASK;
6803 
6804       if (BUSMAIL_HEADER_REJ ==
6805           (buffer2[BUSMAIL_OFFSET_HEADER] & BUSMAIL_HEADER_REJ_MASK)) {
6806 
6807         if (option_debug > 1)
6808           DEBUGA_CVM("CTRL REJ frame...\n", CELLIAX_P_LOG);
6809 
6810         if (0xFF != p->busmail_rxseq_cvm_last) {
6811           buffer2[BUSMAIL_OFFSET_HEADER] |=
6812             (p->busmail_rxseq_cvm_last + 1) & BUSMAIL_HEADER_RXSEQ_MASK;
6813         } else {
6814           if (option_debug > 1)
6815             DEBUGA_CVM
6816               ("Skipping sending REJ, because we just cleared RxSeq counter, and probably it was a packet that is invalid now...\n",
6817                CELLIAX_P_LOG);
6818           return 0;
6819         }
6820 
6821       } else {
6822         buffer2[BUSMAIL_OFFSET_HEADER] |=
6823           (p->busmail_rxseq_cvm_last + 1) & BUSMAIL_HEADER_RXSEQ_MASK;
6824       }
6825     }
6826 
6827     /* update CRC */
6828     busmail_frame->busmail_crc += buffer2[BUSMAIL_OFFSET_HEADER];
6829     buffer2[len - 1] = busmail_frame->busmail_crc;
6830 
6831     if (option_debug > 10) {
6832       char debug_buf[1024];
6833       char *debug_buf_pos;
6834 
6835       memset(debug_buf, 0, 1024);
6836       debug_buf_pos = debug_buf;
6837 
6838       for (i = 0; i < len; i++) {
6839         debug_buf_pos += sprintf(debug_buf_pos, "[%.2X] ", buffer2[i]);
6840         if (debug_buf_pos > (char *) (&debug_buf + 1000))
6841           break;
6842       }
6843 
6844       if (option_debug > 1)
6845         DEBUGA_CVM("CTRL: %s was prepared to send\n", CELLIAX_P_LOG, debug_buf);
6846     }
6847 //    usleep(100);
6848     celliax_serial_send_CVM_BUSMAIL(p, len, buffer2);
6849   }
6850 
6851   return 0;
6852 }
6853 
celliax_serial_send_ctrl_frame_CVM_BUSMAIL(struct celliax_pvt * p,unsigned char FrameType)6854 int celliax_serial_send_ctrl_frame_CVM_BUSMAIL(struct celliax_pvt *p,
6855                                                unsigned char FrameType)
6856 {
6857   /*FrameType parameter is really a busmail header with info neeeded to tell the frame type to send */
6858   struct cvm_busmail_frame busmail_frame;
6859 
6860   switch (FrameType & 0xF0) {
6861     /* only higher nibble is important for us, do not take PF bit into considration */
6862 
6863   case BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_SU_FRAME | BUSMAIL_HEADER_SUID_RR:
6864   case BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_SU_FRAME | BUSMAIL_HEADER_SUID_REJ:
6865   case BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_SU_FRAME | BUSMAIL_HEADER_SUID_RNR:
6866   case BUSMAIL_HEADER_CTRL_FRAME | BUSMAIL_HEADER_CTRL_UN_FRAME | BUSMAIL_HEADER_UNID_SABM:
6867 
6868     busmail_frame.busmail_header =
6869       (FrameType & 0xF8);
6870 
6871     break;
6872 
6873   default:
6874     WARNINGA("UNKNOWN CTRL TYPE specified, sending nothing!!!\n", CELLIAX_P_LOG);
6875     return -1;
6876     break;
6877   }
6878 
6879   busmail_frame.busmail_mail_params_buffer_len = 0;
6880 
6881   /* Sending to CVM */
6882   return celliax_serial_write_CVM_BUSMAIL(p, &busmail_frame);
6883 }
6884 
celliax_serial_send_info_frame_CVM_BUSMAIL(struct celliax_pvt * p,int FrameType,unsigned char ParamsLen,unsigned char * Params)6885 int celliax_serial_send_info_frame_CVM_BUSMAIL(struct celliax_pvt *p, int FrameType,
6886                                                unsigned char ParamsLen,
6887                                                unsigned char *Params)
6888 {
6889   /*FrameType parameter is really a Primitive ID */
6890   struct cvm_busmail_frame busmail_frame;
6891   int i = 0;
6892   busmail_frame.busmail_header =
6893     (BUSMAIL_HEADER_PF_BIT_MASK & 0xFF) | BUSMAIL_HEADER_INFO_FRAME;
6894 
6895   busmail_frame.busmail_mail_primitive[BUSMAIL_MAIL_PRIMITIVE_LSB] = FrameType & 0xFF;
6896   busmail_frame.busmail_mail_primitive[BUSMAIL_MAIL_PRIMITIVE_MSB] =
6897     (FrameType >> 8) & 0xFF;
6898 
6899   busmail_frame.busmail_mail_program_id = BUSMAIL_MAIL_PROGRAM_ID;
6900   busmail_frame.busmail_mail_task_id = BUSMAIL_MAIL_TASK_ID;
6901 
6902   for (i = 0; i < ParamsLen; i++) {
6903     busmail_frame.busmail_mail_params_buffer[i] = Params[i];
6904   }
6905 
6906   busmail_frame.busmail_mail_params_buffer_len = ParamsLen;
6907 
6908   /* Sending to CVM */
6909   return celliax_serial_write_CVM_BUSMAIL(p, &busmail_frame);
6910 }
6911 
celliax_serial_lists_free_CVM_BUSMAIL(struct celliax_pvt * p)6912 int celliax_serial_lists_free_CVM_BUSMAIL(struct celliax_pvt *p)
6913 {
6914   struct cvm_busmail_msg *ptr, *prev;
6915 /*
6916   if (option_debug > 1) {
6917     DEBUGA_CVM("START FREEING OUTGOING\n", CELLIAX_P_LOG);
6918     DEBUGA_CVM("OUTGOING list:\n", CELLIAX_P_LOG);
6919     celliax_serial_list_print_CVM_BUSMAIL(p, p->cvm_busmail_outgoing_list);
6920     DEBUGA_CVM("OUTGOING list END\n", CELLIAX_P_LOG);
6921   }
6922 */
6923   ptr = p->cvm_busmail_outgoing_list;
6924 
6925   if (ptr) {
6926     while (ptr->next != NULL)
6927       ptr = ptr->next;
6928 
6929     while (ptr->previous != NULL) {
6930 
6931       if (option_debug > 1)
6932         DEBUGA_CVM("FREED \n", CELLIAX_P_LOG);
6933 
6934       prev = ptr->previous;
6935       free(ptr);
6936       ptr = prev;
6937     }
6938 
6939     free(ptr);
6940   }
6941 
6942   if (option_debug > 1)
6943     DEBUGA_CVM("LAST FREED \n", CELLIAX_P_LOG);
6944 
6945   p->cvm_busmail_outgoing_list = NULL;
6946   p->cvm_busmail_outgoing_list = celliax_serial_list_init_CVM_BUSMAIL(p);
6947 
6948   if (option_debug > 1) {
6949     DEBUGA_CVM("OUTGOING list:\n", CELLIAX_P_LOG);
6950     celliax_serial_list_print_CVM_BUSMAIL(p, p->cvm_busmail_outgoing_list);
6951     DEBUGA_CVM("OUTGOING list END\n", CELLIAX_P_LOG);
6952     DEBUGA_CVM("STARTING FREE INGOING\n", CELLIAX_P_LOG);
6953   }
6954 
6955   return 0;
6956 }
6957 
celliax_serial_list_init_CVM_BUSMAIL(struct celliax_pvt * p)6958 struct cvm_busmail_msg *celliax_serial_list_init_CVM_BUSMAIL(struct celliax_pvt *p)
6959 {
6960   struct cvm_busmail_msg *list;
6961   list = p->cvm_busmail_outgoing_list;
6962 
6963   PUSHA_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6964   CVM_LOKKA(&p->cvm_busmail_outgoing_list_lock);
6965 
6966   if (list == NULL) {
6967     list = malloc(sizeof(*(list)));
6968     list->valid = 0;
6969     list->busmail_msg_len = 0;
6970     list->acknowledged = 0;
6971     list->how_many_sent = 0;
6972     list->sent = 0;
6973     list->tv_sec = 0;
6974     list->tv_usec = 0;
6975     list->next = NULL;
6976     list->previous = NULL;
6977   }
6978 
6979   if (list->valid != 0) {
6980     struct cvm_busmail_msg *new;
6981     new = malloc(sizeof(*new));
6982     new->valid = 0;
6983     new->busmail_msg_len = 0;
6984     new->acknowledged = 0;
6985     new->how_many_sent = 0;
6986     new->sent = 0;
6987     new->tv_sec = 0;
6988     new->tv_usec = 0;
6989     new->next = NULL;
6990     new->previous = list;
6991     list->next = new;
6992     list = new;
6993   }
6994 
6995   CVM_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6996   POPPA_UNLOCKA(&p->cvm_busmail_outgoing_list_lock);
6997 
6998   return list;
6999 }
7000 
celliax_serial_list_print_CVM_BUSMAIL(struct celliax_pvt * p,struct cvm_busmail_msg * list)7001 int celliax_serial_list_print_CVM_BUSMAIL(struct celliax_pvt *p,
7002                                           struct cvm_busmail_msg *list)
7003 {
7004   struct cvm_busmail_msg *ptr;
7005   ptr = list;
7006 
7007   if (ptr) {
7008     while (ptr->next != NULL)
7009       ptr = ptr->next;
7010 
7011     while (ptr) {
7012 
7013       if (option_debug > 3)
7014         DEBUGA_CVM
7015           ("PTR msg is: %d, seqnum is %.2X, tv_sec is %d, tv_usec is %d, acknowledged is: %d,"
7016            " sent is:%d, how_many_sent is: %d\n", CELLIAX_P_LOG, ptr->valid,
7017            /*ptr->seqnum */ 44,
7018            ptr->tv_sec, ptr->tv_usec, ptr->acknowledged, ptr->sent, ptr->how_many_sent);
7019 
7020       ptr = ptr->previous;
7021     }
7022   }
7023 
7024   return 0;
7025 }
7026 
7027 #endif /* CELLIAX_CVM */
7028