fixes
[lcr.git] / ie.cpp
1
2 /*****************************************************************************\
3 **                                                                           **
4 ** PBX4Linux                                                                 **
5 **                                                                           **
6 **---------------------------------------------------------------------------**
7 ** Copyright: Andreas Eversberg                                              **
8 **                                                                           **
9 ** information elements encode and decode                                    **
10 **                                                                           **
11 \*****************************************************************************/ 
12
13 /*
14  the pointer of enc_ie_* always points to the IE itself
15  if qi is not NULL (TE-mode), offset is set
16 */
17
18 /* support stuff */
19 static void strnncpy(unsigned char *dest, unsigned char *src, int len, int dst_len)
20 {
21         if (len > dst_len-1)
22                 len = dst_len-1;
23         UNCPY((char *)dest, (char *)src, len);
24         dest[len] = '\0';
25 }
26
27
28 /* IE_COMPLETE */
29 void Pdss1::enc_ie_complete(unsigned char **ntmode, msg_t *msg, int complete)
30 {
31         unsigned char *p;
32         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
33
34         if (complete<0 || complete>1)
35         {
36                 PERROR("complete(%d) is out of range.\n", complete);
37                 return;
38         }
39
40         if (complete)
41         {
42                 add_trace("complete", NULL, NULL);
43                 p = msg_put(msg, 1);
44                 if (p_m_d_ntmode)
45                 {
46                         *ntmode = p;
47                 } else
48                         qi->sending_complete.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
49                 p[0] = IE_COMPLETE;
50         }
51 }
52
53 void Pdss1::dec_ie_complete(unsigned char *p, Q931_info_t *qi, int *complete)
54 {
55         *complete = 0;
56         if (!p_m_d_ntmode)
57         {
58                 if (qi->sending_complete.off)
59                         *complete = 1;
60         } else
61         if (p)
62                 *complete = 1;
63
64         if (*complete)
65                 add_trace("complete", NULL, NULL);
66 }
67
68
69 /* IE_BEARER */
70 void Pdss1::enc_ie_bearer(unsigned char **ntmode, msg_t *msg, int coding, int capability, int mode, int rate, int multi, int user)
71 {
72         unsigned char *p;
73         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
74         int l;
75
76         if (coding<0 || coding>3)
77         {
78                 PERROR("coding(%d) is out of range.\n", coding);
79                 return;
80         }
81         if (capability<0 || capability>31)
82         {
83                 PERROR("capability(%d) is out of range.\n", capability);
84                 return;
85         }
86         if (mode<0 || mode>3)
87         {
88                 PERROR("mode(%d) is out of range.\n", mode);
89                 return;
90         }
91         if (rate<0 || rate>31)
92         {
93                 PERROR("rate(%d) is out of range.\n", rate);
94                 return;
95         }
96         if (multi>127)
97         {
98                 PERROR("multi(%d) is out of range.\n", multi);
99                 return;
100         }
101         if (user>31)
102         {
103                 PERROR("user L1(%d) is out of range.\n", user);
104                 return;
105         }
106         if (rate!=24 && multi>=0)
107         {
108                 PERROR("multi(%d) is only possible if rate(%d) would be 24.\n", multi, rate);
109                 multi = -1;
110         }
111
112         add_trace("bearer", "coding", "%d", coding);
113         add_trace("bearer", "capability", "%d", capability);
114         add_trace("bearer", "mode", "%d", mode);
115         add_trace("bearer", "rate", "%d", rate);
116         add_trace("bearer", "multi", "%d", multi);
117         add_trace("bearer", "user", "%d", user);
118
119         l = 2 + (multi>=0) + (user>=0);
120         p = msg_put(msg, l+2);
121         if (p_m_d_ntmode)
122                 *ntmode = p+1;
123         else
124                 qi->bearer_capability.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
125         p[0] = IE_BEARER;
126         p[1] = l;
127         p[2] = 0x80 + (coding<<5) + capability;
128         p[3] = 0x80 + (mode<<5) + rate;
129         if (multi >= 0)
130                 p[4] = 0x80 + multi;
131         if (user >= 0)
132                 p[4+(multi>=0)] = 0xa0 + user;
133 }
134
135 void Pdss1::dec_ie_bearer(unsigned char *p, Q931_info_t *qi, int *coding, int *capability, int *mode, int *rate, int *multi, int *user)
136 {
137         *coding = -1;
138         *capability = -1;
139         *mode = -1;
140         *rate = -1;
141         *multi = -1;
142         *user = -1;
143
144         if (!p_m_d_ntmode)
145         {
146                 p = NULL;
147                 if (qi->bearer_capability.off)
148                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->bearer_capability.off + 1;
149         }
150         if (!p)
151                 return;
152         if (p[0] < 2)
153         {
154                 PERROR("IE too short (%d).\n", p[0]);
155                 return;
156         }
157
158         *coding = (p[1]&0x60) >> 5;
159         *capability = p[1] & 0x1f;
160         if (p[0]>=2)
161         {
162                 *mode = (p[2]&0x60) >> 5;
163                 *rate = p[2] & 0x1f;
164         }
165         if (p[0]>=3 && *rate==0x18)
166         {
167                 *multi = p[3] & 0x7f;
168                 if (p[0]>=4)
169                         *user = p[4] & 0x1f;
170         } else
171         {
172                 if (p[0]>=3)
173                         *user = p[3] & 0x1f;
174         }
175
176         add_trace("bearer", "coding", "%d", *coding);
177         add_trace("bearer", "capability", "%d", *capability);
178         add_trace("bearer", "mode", "%d", *mode);
179         add_trace("bearer", "rate", "%d", *rate);
180         add_trace("bearer", "multi", "%d", *multi);
181         add_trace("bearer", "user", "%d", *user);
182 }
183
184
185 /* IE_HLC */
186 void Pdss1::enc_ie_hlc(unsigned char **ntmode, msg_t *msg, int coding, int interpretation, int presentation, int hlc, int exthlc)
187 {
188         unsigned char *p;
189         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
190         int l;
191
192         if (coding<0 || coding>3)
193         {
194                 PERROR("coding(%d) is out of range.\n", coding);
195                 return;
196         }
197         if (interpretation<0 || interpretation>7)
198         {
199                 PERROR("interpretation(%d) is out of range.\n", interpretation);
200                 return;
201         }
202         if (presentation<0 || presentation>3)
203         {
204                 PERROR("presentation(%d) is out of range.\n", presentation);
205                 return;
206         }
207         if (hlc<0 || hlc>127)
208         {
209                 PERROR("hlc(%d) is out of range.\n", hlc);
210                 return;
211         }
212         if (exthlc>127)
213         {
214                 PERROR("hlc(%d) is out of range.\n", exthlc);
215                 return;
216         }
217
218         add_trace("hlc", "coding", "%d", coding);
219         add_trace("hlc", "interpretation", "%d", interpretation);
220         add_trace("hlc", "presentation", "%d", presentation);
221         add_trace("hlc", "hlc", "%d", hlc);
222         if (exthlc >= 0)
223                 add_trace("hlc", "exthlc", "%d", exthlc);
224
225         l = 2 + (exthlc>=0);
226         p = msg_put(msg, l+2);
227         if (p_m_d_ntmode)
228                 *ntmode = p+1;
229         else
230                 qi->hlc.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
231         p[0] = IE_HLC;
232         p[1] = l;
233         p[2] = 0x80 + (coding<<5) + (interpretation<<2) + presentation;
234         if (exthlc >= 0)
235         {
236                 p[3] = hlc;
237                 p[4] = 0x80 + exthlc;
238         } else
239                 p[3] = 0x80 + hlc;
240 }
241
242 void Pdss1::dec_ie_hlc(unsigned char *p, Q931_info_t *qi, int *coding, int *interpretation, int *presentation, int *hlc, int *exthlc)
243 {
244         *coding = -1;
245         *interpretation = -1;
246         *presentation = -1;
247         *hlc = -1;
248         *exthlc = -1;
249
250         if (!p_m_d_ntmode)
251         {
252                 p = NULL;
253                 if (qi->hlc.off)
254                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->hlc.off + 1;
255         }
256         if (!p)
257                 return;
258         if (p[0] < 2)
259         {
260                 PERROR("IE too short (%d).\n", p[0]);
261                 return;
262         }
263
264         *coding = (p[1]&0x60) >> 5;
265         *interpretation = (p[1]&0x1c) >> 2;
266         *presentation = p[1] & 0x03;
267         *hlc = p[2] & 0x7f;
268         if (p[0]>=3)
269         {
270                 *exthlc = p[3] & 0x7f;
271         }
272
273         add_trace("hlc", "coding", "%d", *coding);
274         add_trace("hlc", "interpretation", "%d", *interpretation);
275         add_trace("hlc", "presentation", "%d", *presentation);
276         add_trace("hlc", "hlc", "%d", *hlc);
277         if (*exthlc >= 0)
278                 add_trace("hlc", "exthlc", "%d", *exthlc);
279 }
280
281
282 /* IE_CALL_ID */
283 void Pdss1::enc_ie_call_id(unsigned char **ntmode, msg_t *msg, unsigned char *callid, int callid_len)
284 {
285         unsigned char *p;
286         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
287         int l;
288
289         char buffer[25];
290         int i;
291
292         if (!callid || callid_len<=0)
293         {
294                 return;
295         }
296         if (callid_len > 8)
297         {
298                 PERROR("callid_len(%d) is out of range.\n", callid_len);
299                 return;
300         }
301
302         i = 0;
303         while(i < callid_len)
304         {
305                 UPRINT(buffer+(i*3), " %02x", callid[i]);
306                 i++;
307         }
308                 
309         add_trace("callid", NULL, "%s", buffer[0]?buffer+1:"<none>");
310
311         l = callid_len;
312         p = msg_put(msg, l+2);
313         if (p_m_d_ntmode)
314                 *ntmode = p+1;
315         else
316                 qi->call_id.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
317         p[0] = IE_CALL_ID;
318         p[1] = l;
319         memcpy(p+2, callid, callid_len);
320 }
321
322 void Pdss1::dec_ie_call_id(unsigned char *p, Q931_info_t *qi, unsigned char *callid, int *callid_len)
323 {
324         char buffer[25];
325         int i;
326
327         *callid_len = -1;
328
329         if (!p_m_d_ntmode)
330         {
331                 p = NULL;
332                 if (qi->call_id.off)
333                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->call_id.off + 1;
334         }
335         if (!p)
336                 return;
337         if (p[0] > 8)
338         {
339                 PERROR("IE too long (%d).\n", p[0]);
340                 return;
341         }
342
343         *callid_len = p[0];
344         memcpy(callid, p+1, *callid_len);
345
346         i = 0;
347         while(i < *callid_len)
348         {
349                 UPRINT(buffer+(i*3), " %02x", callid[i]);
350                 i++;
351         }
352                 
353         add_trace("callid", NULL, "%s", buffer[0]?buffer+1:"<none>");
354 }
355
356
357 /* IE_CALLED_PN */
358 void Pdss1::enc_ie_called_pn(unsigned char **ntmode, msg_t *msg, int type, int plan, unsigned char *number)
359 {
360         unsigned char *p;
361         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
362         int l;
363
364         if (type<0 || type>7)
365         {
366                 PERROR("type(%d) is out of range.\n", type);
367                 return;
368         }
369         if (plan<0 || plan>15)
370         {
371                 PERROR("plan(%d) is out of range.\n", plan);
372                 return;
373         }
374         if (!number[0])
375         {
376                 PERROR("number is not given.\n");
377                 return;
378         }
379
380         add_trace("called_pn", "type", "%d", type);
381         add_trace("called_pn", "plan", "%d", plan);
382         add_trace("called_pn", "number", "%s", number);
383
384         l = 1+strlen((char *)number);
385         p = msg_put(msg, l+2);
386         if (p_m_d_ntmode)
387                 *ntmode = p+1;
388         else
389                 qi->called_nr.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
390         p[0] = IE_CALLED_PN;
391         p[1] = l;
392         p[2] = 0x80 + (type<<4) + plan;
393         UNCPY((char *)p+3, (char *)number, strlen((char *)number));
394 }
395
396 void Pdss1::dec_ie_called_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, unsigned char *number, int number_len)
397 {
398         *type = -1;
399         *plan = -1;
400         *number = '\0';
401
402         if (!p_m_d_ntmode)
403         {
404                 p = NULL;
405                 if (qi->called_nr.off)
406                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->called_nr.off + 1;
407         }
408         if (!p)
409                 return;
410         if (p[0] < 2)
411         {
412                 PERROR("IE too short (%d).\n", p[0]);
413                 return;
414         }
415
416         *type = (p[1]&0x70) >> 4;
417         *plan = p[1] & 0xf;
418         strnncpy(number, p+2, p[0]-1, number_len);
419
420         add_trace("called_pn", "type", "%d", *type);
421         add_trace("called_pn", "plan", "%d", *plan);
422         add_trace("called_pn", "number", "%s", number);
423 }
424
425
426 /* IE_CALLING_PN */
427 void Pdss1::enc_ie_calling_pn(unsigned char **ntmode, msg_t *msg, int type, int plan, int present, int screen, unsigned char *number)
428 {
429         unsigned char *p;
430         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
431         int l;
432
433         if (type<0 || type>7)
434         {
435                 PERROR("type(%d) is out of range.\n", type);
436                 return;
437         }
438         if (plan<0 || plan>15)
439         {
440                 PERROR("plan(%d) is out of range.\n", plan);
441                 return;
442         }
443         if (present>3)
444         {
445                 PERROR("present(%d) is out of range.\n", present);
446                 return;
447         }
448         if (present >= 0) if (screen<0 || screen>3)
449         {
450                 PERROR("screen(%d) is out of range.\n", screen);
451                 return;
452         }
453
454         add_trace("calling_pn", "type", "%d", type);
455         add_trace("calling_pn", "plan", "%d", plan);
456         add_trace("calling_pn", "present", "%d", present);
457         add_trace("calling_pn", "screen", "%d", screen);
458         add_trace("calling_pn", "number", "%s", number);
459
460         l = 1;
461         if (number) if (number[0])
462                 l += strlen((char *)number);
463         if (present >= 0)
464                 l += 1;
465         p = msg_put(msg, l+2);
466         if (p_m_d_ntmode)
467                 *ntmode = p+1;
468         else
469                 qi->calling_nr.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
470         p[0] = IE_CALLING_PN;
471         p[1] = l;
472         if (present >= 0)
473         {
474                 p[2] = 0x00 + (type<<4) + plan;
475                 p[3] = 0x80 + (present<<5) + screen;
476                 if (number) if (number[0])
477                         UNCPY((char *)p+4, (char *)number, strlen((char *)number));
478         } else
479         {
480                 p[2] = 0x80 + (type<<4) + plan;
481                 if (number) if (number[0])
482                         UNCPY((char *)p+3, (char *)number, strlen((char *)number));
483         }
484 }
485
486 void Pdss1::dec_ie_calling_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, int *screen, unsigned char *number, int number_len)
487 {
488         *type = -1;
489         *plan = -1;
490         *present = -1;
491         *screen = -1;
492         *number = '\0';
493
494         if (!p_m_d_ntmode)
495         {
496                 p = NULL;
497                 if (qi->calling_nr.off)
498                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->calling_nr.off + 1;
499         }
500         if (!p)
501                 return;
502         if (p[0] < 1)
503         {
504                 PERROR("IE too short (%d).\n", p[0]);
505                 return;
506         }
507
508         *type = (p[1]&0x70) >> 4;
509         *plan = p[1] & 0xf;
510         if (!(p[1] & 0x80))
511         {
512                 if (p[0] < 2)
513                 {
514                         PERROR("IE too short (%d).\n", p[0]);
515                         return;
516                 }
517                 *present = (p[2]&0x60) >> 5;
518                 *screen = p[2] & 0x3;
519                 strnncpy(number, p+3, p[0]-2, number_len);
520         } else
521         {
522                 strnncpy(number, p+2, p[0]-1, number_len);
523         }
524
525         add_trace("calling_pn", "type", "%d", *type);
526         add_trace("calling_pn", "plan", "%d", *plan);
527         add_trace("calling_pn", "present", "%d", *present);
528         add_trace("calling_pn", "screen", "%d", *screen);
529         add_trace("calling_pn", "number", "%s", number);
530 }
531
532
533 /* IE_CONNECTED_PN */
534 void Pdss1::enc_ie_connected_pn(unsigned char **ntmode, msg_t *msg, int type, int plan, int present, int screen, unsigned char *number)
535 {
536         unsigned char *p;
537         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
538         int l;
539
540         if (type<0 || type>7)
541         {
542                 PERROR("type(%d) is out of range.\n", type);
543                 return;
544         }
545         if (plan<0 || plan>15)
546         {
547                 PERROR("plan(%d) is out of range.\n", plan);
548                 return;
549         }
550         if (present>3)
551         {
552                 PERROR("present(%d) is out of range.\n", present);
553                 return;
554         }
555         if (present >= 0) if (screen<0 || screen>3)
556         {
557                 PERROR("screen(%d) is out of range.\n", screen);
558                 return;
559         }
560
561         add_trace("connect_pn", "type", "%d", type);
562         add_trace("connect_pn", "plan", "%d", plan);
563         add_trace("connect_pn", "present", "%d", present);
564         add_trace("connect_pn", "screen", "%d", screen);
565         add_trace("connect_pn", "number", "%s", number);
566
567         l = 1;
568         if (number) if (number[0])
569                 l += strlen((char *)number);
570         if (present >= 0)
571                 l += 1;
572         p = msg_put(msg, l+2);
573         if (p_m_d_ntmode)
574                 *ntmode = p+1;
575         else
576                 qi->connected_nr.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
577         p[0] = IE_CONNECT_PN;
578         p[1] = l;
579         if (present >= 0)
580         {
581                 p[2] = 0x00 + (type<<4) + plan;
582                 p[3] = 0x80 + (present<<5) + screen;
583                 if (number) if (number[0])
584                         UNCPY((char *)p+4, (char *)number, strlen((char *)number));
585         } else
586         {
587                 p[2] = 0x80 + (type<<4) + plan;
588                 if (number) if (number[0])
589                         UNCPY((char *)p+3, (char *)number, strlen((char *)number));
590         }
591 }
592
593 void Pdss1::dec_ie_connected_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, int *screen, unsigned char *number, int number_len)
594 {
595         *type = -1;
596         *plan = -1;
597         *present = -1;
598         *screen = -1;
599         *number = '\0';
600
601         if (!p_m_d_ntmode)
602         {
603                 p = NULL;
604                 if (qi->connected_nr.off)
605                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->connected_nr.off + 1;
606         }
607         if (!p)
608                 return;
609         if (p[0] < 1)
610         {
611                 PERROR("IE too short (%d).\n", p[0]);
612                 return;
613         }
614
615         *type = (p[1]&0x70) >> 4;
616         *plan = p[1] & 0xf;
617         if (!(p[1] & 0x80))
618         {
619                 if (p[0] < 2)
620                 {
621                         PERROR("IE too short (%d).\n", p[0]);
622                         return;
623                 }
624                 *present = (p[2]&0x60) >> 5;
625                 *screen = p[2] & 0x3;
626                 strnncpy(number, p+3, p[0]-2, number_len);
627         } else
628         {
629                 strnncpy(number, p+2, p[0]-1, number_len);
630         }
631
632         add_trace("connect_pn", "type", "%d", *type);
633         add_trace("connect_pn", "plan", "%d", *plan);
634         add_trace("connect_pn", "present", "%d", *present);
635         add_trace("connect_pn", "screen", "%d", *screen);
636         add_trace("connect_pn", "number", "%s", number);
637 }
638
639
640 /* IE_CAUSE */
641 void Pdss1::enc_ie_cause(unsigned char **ntmode, msg_t *msg, int location, int cause)
642 {
643         unsigned char *p;
644         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
645         int l;
646
647         if (location<0 || location>7)
648         {
649                 PERROR("location(%d) is out of range.\n", location);
650                 return;
651         }
652         if (cause<0 || cause>127)
653         {
654                 PERROR("cause(%d) is out of range.\n", cause);
655                 return;
656         }
657
658         add_trace("cause", "location", "%d", location);
659         add_trace("cause", "value", "%d", cause);
660
661         l = 2;
662         p = msg_put(msg, l+2);
663         if (p_m_d_ntmode)
664                 *ntmode = p+1;
665         else
666                 qi->cause.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
667         p[0] = IE_CAUSE;
668         p[1] = l;
669         p[2] = 0x80 + location;
670         p[3] = 0x80 + cause;
671 }
672 void enc_ie_cause_standalone(unsigned char **ntmode, msg_t *msg, int location, int cause)
673 {
674         unsigned char *p = msg_put(msg, 4);
675         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
676         if (ntmode)
677                 *ntmode = p+1;
678         else
679                 qi->cause.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
680         p[0] = IE_CAUSE;
681         p[1] = 2;
682         p[2] = 0x80 + location;
683         p[3] = 0x80 + cause;
684 }
685
686
687 void Pdss1::dec_ie_cause(unsigned char *p, Q931_info_t *qi, int *location, int *cause)
688 {
689         *location = -1;
690         *cause = -1;
691
692         if (!p_m_d_ntmode)
693         {
694                 p = NULL;
695                 if (qi->cause.off)
696                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->cause.off + 1;
697         }
698         if (!p)
699                 return;
700         if (p[0] < 2)
701         {
702                 PERROR("IE too short (%d).\n", p[0]);
703                 return;
704         }
705
706         *location = p[1] & 0x0f;
707         *cause = p[2] & 0x7f;
708
709         add_trace("cause", "location", "%d", *location);
710         add_trace("cause", "value", "%d", *cause);
711 }
712
713
714 /* IE_CHANNEL_ID */
715 void Pdss1::enc_ie_channel_id(unsigned char **ntmode, msg_t *msg, int exclusive, int channel)
716 {
717         unsigned char *p;
718         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
719         int l;
720         int pri = p_m_mISDNport->pri;
721
722         if (exclusive<0 || exclusive>1)
723         {
724                 PERROR("exclusive(%d) is out of range.\n", exclusive);
725                 return;
726         }
727         if ((channel<=0 && channel!=CHANNEL_NO && channel!=CHANNEL_ANY)
728          || (!pri && channel>2)
729          || (pri && channel>127)
730          || (pri && channel==16))
731         {
732                 PERROR("channel(%d) is out of range.\n", channel);
733                 return;
734         }
735
736         add_trace("channel_id", "exclusive", "%d", exclusive);
737         switch(channel)
738         {
739                 case CHANNEL_ANY:
740                 add_trace("channel_id", "channel", "any channel");
741                 break;
742                 case CHANNEL_NO:
743                 add_trace("channel_id", "channel", "no channel");
744                 break;
745                 default:
746                 add_trace("channel_id", "channel", "%d", channel);
747         }
748
749         if (!pri)
750         {
751                 /* BRI */
752                 l = 1;
753                 p = msg_put(msg, l+2);
754                 if (p_m_d_ntmode)
755                         *ntmode = p+1;
756                 else
757                         qi->channel_id.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
758                 p[0] = IE_CHANNEL_ID;
759                 p[1] = l;
760                 if (channel == CHANNEL_NO)
761                         channel = 0;
762                 else if (channel == CHANNEL_ANY)
763                         channel = 3;
764                 p[2] = 0x80 + (exclusive<<3) + channel;
765         } else
766         {
767                 /* PRI */
768                 if (channel == CHANNEL_NO) /* no channel */
769                         return; /* IE not present */
770                 if (channel == CHANNEL_ANY) /* any channel */
771                 {
772                         l = 1;
773                         p = msg_put(msg, l+2);
774                         if (p_m_d_ntmode)
775                                 *ntmode = p+1;
776                         else
777                                 qi->channel_id.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
778                         p[0] = IE_CHANNEL_ID;
779                         p[1] = l;
780                         p[2] = 0x80 + 0x20 + 0x03;
781                         return; /* end */
782                 }
783                 l = 3;
784                 p = msg_put(msg, l+2);
785                 if (p_m_d_ntmode)
786                         *ntmode = p+1;
787                 else
788                         qi->channel_id.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
789                 p[0] = IE_CHANNEL_ID;
790                 p[1] = l;
791                 p[2] = 0x80 + 0x20 + (exclusive<<3) + 0x01;
792                 p[3] = 0x80 + 3; /* CCITT, Number, B-type */
793                 p[4] = 0x80 + channel;
794         }
795 }
796
797 void Pdss1::dec_ie_channel_id(unsigned char *p, Q931_info_t *qi, int *exclusive, int *channel)
798 {
799         int pri = p_m_mISDNport->pri;
800
801         *exclusive = -1;
802         *channel = -1;
803
804         if (!p_m_d_ntmode)
805         {
806                 p = NULL;
807                 if (qi->channel_id.off)
808                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->channel_id.off + 1;
809         }
810         if (!p)
811                 return;
812         if (p[0] < 1)
813         {
814                 PERROR("IE too short (%d).\n", p[0]);
815                 return;
816         }
817
818         if (p[1] & 0x40)
819         {
820                 PERROR("refering to channels of other interfaces is not supported.\n");
821                 return;
822         }
823         if (p[1] & 0x04)
824         {
825                 PERROR("using d-channel is not supported.\n");
826                 return;
827         }
828
829         *exclusive = (p[1]&0x08) >> 3;
830         if (!pri)
831         {
832                 /* BRI */
833                 if (p[1] & 0x20)
834                 {
835                         PERROR("extended channel ID with non PRI interface.\n");
836                         return;
837                 }
838                 *channel = p[1] & 0x03;
839                 if (*channel == 3)
840                         *channel = CHANNEL_ANY;
841                 else if (*channel == 0)
842                         *channel = CHANNEL_NO;
843         } else
844         {
845                 /* PRI */
846                 if (p[0] < 1)
847                 {
848                         PERROR("IE too short for PRI (%d).\n", p[0]);
849                         return;
850                 }
851                 if (!(p[1] & 0x20))
852                 {
853                         PERROR("basic channel ID with PRI interface.\n");
854                         return;
855                 }
856                 if ((p[1]&0x03) == 0x00)
857                 {
858                         /* no channel */
859                         *channel = CHANNEL_NO;
860                         return;
861                 }
862                 if ((p[1]&0x03) == 0x03)
863                 {
864                         /* any channel */
865                         *channel = CHANNEL_ANY;
866                         return;
867                 }
868                 if (p[0] < 3)
869                 {
870                         PERROR("%s: ERROR: IE too short for PRI with channel(%d).\n", __FUNCTION__, p[0]);
871                         return;
872                 }
873                 if (p[2] & 0x10)
874                 {
875                         PERROR("channel map not supported.\n");
876                         return;
877                 }
878                 *channel = p[3] & 0x7f;
879                 if (*channel<1 | *channel==16)
880                 {
881                         PERROR("PRI interface channel out of range (%d).\n", *channel);
882                         return;
883                 }
884         }
885
886         add_trace("channel_id", "exclusive", "%d", *exclusive);
887         switch(*channel)
888         {
889                 case CHANNEL_ANY:
890                 add_trace("channel_id", "channel", "any channel");
891                 break;
892                 case CHANNEL_NO:
893                 add_trace("channel_id", "channel", "no channel");
894                 break;
895                 default:
896                 add_trace("channel_id", "channel", "%d", *channel);
897         }
898 }
899
900
901 /* IE_DATE */
902 void Pdss1::enc_ie_date(unsigned char **ntmode, msg_t *msg, time_t ti, int no_seconds)
903 {
904         unsigned char *p;
905         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
906         int l;
907
908         struct tm *tm;
909
910         tm = localtime(&ti);
911         if (!tm)
912         {
913                 PERROR("localtime() returned NULL.\n");
914                 return;
915         }
916
917         add_trace("date", "day", "%d.%d.%d", tm->tm_mday, tm->tm_mon+1, tm->tm_year%100);
918         add_trace("date", "time", "%d:%d:%d", tm->tm_hour, tm->tm_min, tm->tm_sec);
919
920         l = 5 + (!no_seconds);
921         p = msg_put(msg, l+2);
922         if (p_m_d_ntmode)
923                 *ntmode = p+1;
924         else
925                 qi->date.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
926         p[0] = IE_DATE;
927         p[1] = l;
928         p[2] = tm->tm_year % 100;
929         p[3] = tm->tm_mon + 1;
930         p[4] = tm->tm_mday;
931         p[5] = tm->tm_hour;
932         p[6] = tm->tm_min;
933         if (!no_seconds)
934                 p[7] = tm->tm_sec;
935 }
936
937
938 /* IE_DISPLAY */
939 void Pdss1::enc_ie_display(unsigned char **ntmode, msg_t *msg, unsigned char *display)
940 {
941         unsigned char *p;
942         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
943         int l;
944
945         if (!display[0])
946         {
947                 PERROR("display text not given.\n");
948                 return;
949         }
950
951         if (strlen((char *)display) > 80)
952         {
953                 PERROR("display text too long (max 80 chars), cutting.\n");
954                 display[80] = '\0';
955         }
956
957         add_trace("display", NULL, "%s", display);
958
959         l = strlen((char *)display);
960         p = msg_put(msg, l+2);
961         if (p_m_d_ntmode)
962                 *ntmode = p+1;
963         else
964                 qi->display.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
965         p[0] = IE_DISPLAY;
966         p[1] = l;
967         UNCPY((char *)p+2, (char *)display, strlen((char *)display));
968 }
969
970 void Pdss1::dec_ie_display(unsigned char *p, Q931_info_t *qi, unsigned char *display, int display_len)
971 {
972         *display = '\0';
973
974         if (!p_m_d_ntmode)
975         {
976                 p = NULL;
977                 if (qi->display.off)
978                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->display.off + 1;
979         }
980         if (!p)
981                 return;
982         if (p[0] < 1)
983         {
984                 PERROR("IE too short (%d).\n", p[0]);
985                 return;
986         }
987
988         strnncpy(display, p+1, p[0], display_len);
989
990         add_trace("display", NULL, "%s", display);
991 }
992
993
994 /* IE_KEYPAD */
995 void Pdss1::enc_ie_keypad(unsigned char **ntmode, msg_t *msg, unsigned char *keypad)
996 {
997         unsigned char *p;
998         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
999         int l;
1000
1001         if (!keypad[0])
1002         {
1003                 PERROR("keypad info not given.\n");
1004                 return;
1005         }
1006
1007         add_trace("keypad", NULL, "%s", keypad);
1008
1009         l = strlen((char *)keypad);
1010         p = msg_put(msg, l+2);
1011         if (p_m_d_ntmode)
1012                 *ntmode = p+1;
1013         else
1014                 qi->keypad.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1015         p[0] = IE_KEYPAD;
1016         p[1] = l;
1017         UNCPY((char *)p+2, (char *)keypad, strlen((char *)keypad));
1018 }
1019
1020 void Pdss1::dec_ie_keypad(unsigned char *p, Q931_info_t *qi, unsigned char *keypad, int keypad_len)
1021 {
1022         *keypad = '\0';
1023
1024         if (!p_m_d_ntmode)
1025         {
1026                 p = NULL;
1027                 if (qi->keypad.off)
1028                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->keypad.off + 1;
1029         }
1030         if (!p)
1031                 return;
1032         if (p[0] < 1)
1033         {
1034                 PERROR("IE too short (%d).\n", p[0]);
1035                 return;
1036         }
1037
1038         strnncpy(keypad, p+1, p[0], keypad_len);
1039
1040         add_trace("keypad", NULL, "%s", keypad);
1041 }
1042
1043
1044 /* IE_NOTIFY */
1045 void Pdss1::enc_ie_notify(unsigned char **ntmode, msg_t *msg, int notify)
1046 {
1047         unsigned char *p;
1048         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
1049         int l;
1050
1051         if (notify<0 || notify>0x7f)
1052         {
1053                 PERROR("notify(%d) is out of range.\n", notify);
1054                 return;
1055         }
1056
1057         add_trace("notify", NULL, "%d", notify);
1058
1059         l = 1;
1060         p = msg_put(msg, l+2);
1061         if (p_m_d_ntmode)
1062                 *ntmode = p+1;
1063         else
1064                 qi->notify.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1065         p[0] = IE_NOTIFY;
1066         p[1] = l;
1067         p[2] = 0x80 + notify;
1068 }
1069
1070 void Pdss1::dec_ie_notify(unsigned char *p, Q931_info_t *qi, int *notify)
1071 {
1072         *notify = -1;
1073
1074         if (!p_m_d_ntmode)
1075         {
1076                 p = NULL;
1077                 if (qi->notify.off)
1078                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->notify.off + 1;
1079         }
1080         if (!p)
1081                 return;
1082         if (p[0] < 1)
1083         {
1084                 PERROR("IE too short (%d).\n", p[0]);
1085                 return;
1086         }
1087
1088         *notify = p[1] & 0x7f;
1089
1090         add_trace("notify", NULL, "%d", *notify);
1091 }
1092
1093
1094 /* IE_PROGRESS */
1095 void Pdss1::enc_ie_progress(unsigned char **ntmode, msg_t *msg, int coding, int location, int progress)
1096 {
1097         unsigned char *p;
1098         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
1099         int l;
1100
1101         if (coding<0 || coding>0x03)
1102         {
1103                 PERROR("coding(%d) is out of range.\n", coding);
1104                 return;
1105         }
1106         if (location<0 || location>0x0f)
1107         {
1108                 PERROR("location(%d) is out of range.\n", location);
1109                 return;
1110         }
1111         if (progress<0 || progress>0x7f)
1112         {
1113                 PERROR("progress(%d) is out of range.\n", progress);
1114                 return;
1115         }
1116
1117         add_trace("progress", "codeing", "%d", coding);
1118         add_trace("progress", "location", "%d", location);
1119         add_trace("progress", "indicator", "%d", progress);
1120
1121         l = 2;
1122         p = msg_put(msg, l+2);
1123         if (p_m_d_ntmode)
1124                 *ntmode = p+1;
1125         else
1126                 qi->progress.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1127         p[0] = IE_PROGRESS;
1128         p[1] = l;
1129         p[2] = 0x80 + (coding<<5) + location;
1130         p[3] = 0x80 + progress;
1131 }
1132
1133 void Pdss1::dec_ie_progress(unsigned char *p, Q931_info_t *qi, int *coding, int *location, int *progress)
1134 {
1135         *coding = -1;
1136         *location = -1;
1137         *progress = -1;
1138
1139         if (!p_m_d_ntmode)
1140         {
1141                 p = NULL;
1142                 if (qi->progress.off)
1143                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->progress.off + 1;
1144         }
1145         if (!p)
1146                 return;
1147         if (p[0] < 1)
1148         {
1149                 PERROR("IE too short (%d).\n", p[0]);
1150                 return;
1151         }
1152
1153         *coding = (p[1]&0x60) >> 5;
1154         *location = p[1] & 0x0f;
1155         *progress = p[2] & 0x7f;
1156
1157         add_trace("progress", "codeing", "%d", *coding);
1158         add_trace("progress", "location", "%d", *location);
1159         add_trace("progress", "indicator", "%d", *progress);
1160 }
1161
1162
1163 /* IE_REDIR_NR (redirecting = during MT_SETUP) */
1164 void Pdss1::enc_ie_redir_nr(unsigned char **ntmode, msg_t *msg, int type, int plan, int present, int screen, int reason, unsigned char *number)
1165 {
1166         unsigned char *p;
1167         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
1168         int l;
1169
1170         if (type<0 || type>7)
1171         {
1172                 PERROR("type(%d) is out of range.\n", type);
1173                 return;
1174         }
1175         if (plan<0 || plan>15)
1176         {
1177                 PERROR("plan(%d) is out of range.\n", plan);
1178                 return;
1179         }
1180         if (present > 3)
1181         {
1182                 PERROR("present(%d) is out of range.\n", present);
1183                 return;
1184         }
1185         if (present >= 0) if (screen<0 || screen>3)
1186         {
1187                 PERROR("screen(%d) is out of range.\n", screen);
1188                 return;
1189         }
1190         if (reason > 0x0f)
1191         {
1192                 PERROR("reason(%d) is out of range.\n", reason);
1193                 return;
1194         }
1195
1196         add_trace("redir'ing", "type", "%d", type);
1197         add_trace("redir'ing", "plan", "%d", plan);
1198         add_trace("redir'ing", "present", "%d", present);
1199         add_trace("redir'ing", "screen", "%d", screen);
1200         add_trace("redir'ing", "reason", "%d", reason);
1201         add_trace("redir'ing", "number", "%s", number);
1202
1203         l = 1;
1204         if (number)
1205                 l += strlen((char *)number);
1206         if (present >= 0)
1207         {
1208                 l += 1;
1209                 if (reason >= 0)
1210                         l += 1;
1211         }
1212         p = msg_put(msg, l+2);
1213         if (p_m_d_ntmode)
1214                 *ntmode = p+1;
1215         else
1216                 qi->redirect_nr.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1217         p[0] = IE_REDIR_NR;
1218         p[1] = l;
1219         if (present >= 0)
1220         {
1221                 if (reason >= 0)
1222                 {
1223                         p[2] = 0x00 + (type<<4) + plan;
1224                         p[3] = 0x00 + (present<<5) + screen;
1225                         p[4] = 0x80 + reason;
1226                         if (number)
1227                                 UNCPY((char *)p+5, (char *)number, strlen((char *)number));
1228                 } else
1229                 {
1230                         p[2] = 0x00 + (type<<4) + plan;
1231                         p[3] = 0x80 + (present<<5) + screen;
1232                         if (number)
1233                                 UNCPY((char *)p+4, (char *)number, strlen((char *)number));
1234                 }
1235         } else
1236         {
1237                 p[2] = 0x80 + (type<<4) + plan;
1238                 if (number) if (number[0])
1239                         UNCPY((char *)p+3, (char *)number, strlen((char *)number));
1240         }
1241 }
1242
1243 void Pdss1::dec_ie_redir_nr(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, int *screen, int *reason, unsigned char *number, int number_len)
1244 {
1245         *type = -1;
1246         *plan = -1;
1247         *present = -1;
1248         *screen = -1;
1249         *reason = -1;
1250         *number = '\0';
1251
1252         if (!p_m_d_ntmode)
1253         {
1254                 p = NULL;
1255                 if (qi->redirect_nr.off)
1256                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->redirect_nr.off + 1;
1257         }
1258         if (!p)
1259                 return;
1260         if (p[0] < 1)
1261         {
1262                 PERROR("IE too short (%d).\n", p[0]);
1263                 return;
1264         }
1265
1266         *type = (p[1]&0x70) >> 4;
1267         *plan = p[1] & 0xf;
1268         if (!(p[1] & 0x80))
1269         {
1270                 *present = (p[2]&0x60) >> 5;
1271                 *screen = p[2] & 0x3;
1272                 if (!(p[2] & 0x80))
1273                 {
1274                         *reason = p[3] & 0x0f;
1275                         strnncpy(number, p+4, p[0]-3, number_len);
1276                 } else
1277                 {
1278                         strnncpy(number, p+3, p[0]-2, number_len);
1279                 }
1280         } else
1281         {
1282                 strnncpy(number, p+2, p[0]-1, number_len);
1283         }
1284
1285         add_trace("redir'ing", "type", "%d", *type);
1286         add_trace("redir'ing", "plan", "%d", *plan);
1287         add_trace("redir'ing", "present", "%d", *present);
1288         add_trace("redir'ing", "screen", "%d", *screen);
1289         add_trace("redir'ing", "reason", "%d", *reason);
1290         add_trace("redir'ing", "number", "%s", number);
1291 }
1292
1293
1294 /* IE_REDIR_DN (redirection = during MT_NOTIFY) */
1295 void Pdss1::enc_ie_redir_dn(unsigned char **ntmode, msg_t *msg, int type, int plan, int present, unsigned char *number)
1296 {
1297         unsigned char *p;
1298         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
1299         int l;
1300
1301         if (type<0 || type>7)
1302         {
1303                 PERROR("type(%d) is out of range.\n", type);
1304                 return;
1305         }
1306         if (plan<0 || plan>15)
1307         {
1308                 PERROR("plan(%d) is out of range.\n", plan);
1309                 return;
1310         }
1311         if (present > 3)
1312         {
1313                 PERROR("present(%d) is out of range.\n", present);
1314                 return;
1315         }
1316
1317         add_trace("redir'tion", "type", "%d", type);
1318         add_trace("redir'tion", "plan", "%d", plan);
1319         add_trace("redir'tion", "present", "%d", present);
1320         add_trace("redir'tion", "number", "%s", number);
1321
1322         l = 1;
1323         if (number)
1324                 l += strlen((char *)number);
1325         if (present >= 0)
1326                 l += 1;
1327         p = msg_put(msg, l+2);
1328         if (p_m_d_ntmode)
1329                 *ntmode = p+1;
1330         else
1331                 qi->redirect_dn.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1332         p[0] = IE_REDIR_DN;
1333         p[1] = l;
1334         if (present >= 0)
1335         {
1336                 p[2] = 0x00 + (type<<4) + plan;
1337                 p[3] = 0x80 + (present<<5);
1338                 if (number)
1339                         UNCPY((char *)p+4, (char *)number, strlen((char *)number));
1340         } else
1341         {
1342                 p[2] = 0x80 + (type<<4) + plan;
1343                 if (number)
1344                         UNCPY((char *)p+3, (char *)number, strlen((char *)number));
1345         }
1346 }
1347
1348 void Pdss1::dec_ie_redir_dn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, unsigned char *number, int number_len)
1349 {
1350         *type = -1;
1351         *plan = -1;
1352         *present = -1;
1353         *number = '\0';
1354
1355         if (!p_m_d_ntmode)
1356         {
1357                 p = NULL;
1358                 if (qi->redirect_dn.off)
1359                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->redirect_dn.off + 1;
1360         }
1361         if (!p)
1362                 return;
1363         if (p[0] < 1)
1364         {
1365                 PERROR("IE too short (%d).\n", p[0]);
1366                 return;
1367         }
1368
1369         *type = (p[1]&0x70) >> 4;
1370         *plan = p[1] & 0xf;
1371         if (!(p[1] & 0x80))
1372         {
1373                 *present = (p[2]&0x60) >> 5;
1374                 strnncpy(number, p+3, p[0]-2, number_len);
1375         } else
1376         {
1377                 strnncpy(number, p+2, p[0]-1, number_len);
1378         }
1379
1380         add_trace("redir'tion", "type", "%d", *type);
1381         add_trace("redir'tion", "plan", "%d", *plan);
1382         add_trace("redir'tion", "present", "%d", *present);
1383         add_trace("redir'tion", "number", "%s", number);
1384 }
1385
1386
1387 /* IE_FACILITY */
1388 void Pdss1::enc_ie_facility(unsigned char **ntmode, msg_t *msg, unsigned char *facility, int facility_len)
1389 {
1390         unsigned char *p;
1391         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
1392         int l;
1393
1394         char buffer[768];
1395         int i;
1396
1397         if (!facility || facility_len<=0)
1398         {
1399                 return;
1400         }
1401
1402         i = 0;
1403         while(i < facility_len)
1404         {
1405                 UPRINT(buffer+(i*3), " %02x", facility[i]);
1406                 i++;
1407         }
1408                 
1409         add_trace("facility", NULL, "%s", buffer+1);
1410
1411         l = facility_len;
1412         p = msg_put(msg, l+2);
1413         if (p_m_d_ntmode)
1414                 *ntmode = p+1;
1415         else
1416                 qi->facility.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1417         p[0] = IE_FACILITY;
1418         p[1] = l;
1419         memcpy(p+2, facility, facility_len);
1420 }
1421
1422 void Pdss1::dec_ie_facility(unsigned char *p, Q931_info_t *qi, unsigned char *facility, int *facility_len)
1423 {
1424         char debug[768];
1425         int i;
1426
1427         *facility_len = 0;
1428
1429         if (!p_m_d_ntmode)
1430         {
1431                 p = NULL;
1432                 if (qi->facility.off)
1433                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->facility.off + 1;
1434         }
1435         if (!p)
1436                 return;
1437
1438         *facility_len = p[0];
1439         memcpy(facility, p+1, *facility_len);
1440
1441         i = 0;
1442         while(i < *facility_len)
1443         {
1444                 UPRINT(debug+(i*3), " %02x", facility[i]);
1445                 i++;
1446         }
1447         debug[i*3] = '\0';
1448                 
1449         add_trace("facility", NULL, "%s", debug[0]?debug+1:"<none>");
1450 }
1451
1452
1453 /* facility for siemens CENTEX (known parts implemented only) */
1454 void Pdss1::enc_facility_centrex(unsigned char **ntmode, msg_t *msg, unsigned char *cnip, int setup)
1455 {
1456         unsigned char centrex[256];
1457         int i = 0;
1458
1459         if (!cnip)
1460                 return;
1461
1462         /* centrex facility */
1463         centrex[i++] = CENTREX_FAC;
1464         centrex[i++] = CENTREX_ID;
1465
1466         /* cnip */
1467         if (strlen((char *)cnip) > 15)
1468         {
1469                 PDEBUG(DEBUG_PORT, "%s: CNIP/CONP text too long (max 13 chars), cutting.\n");
1470                 cnip[15] = '\0';
1471         }
1472         // dunno what the 8 bytes mean
1473         if (setup)
1474         {
1475                 centrex[i++] = 0x17;
1476                 centrex[i++] = 0x02;
1477                 centrex[i++] = 0x02;
1478                 centrex[i++] = 0x44;
1479                 centrex[i++] = 0x18;
1480                 centrex[i++] = 0x02;
1481                 centrex[i++] = 0x01;
1482                 centrex[i++] = 0x09;
1483         } else
1484         {
1485                 centrex[i++] = 0x18;
1486                 centrex[i++] = 0x02;
1487                 centrex[i++] = 0x02;
1488                 centrex[i++] = 0x81;
1489                 centrex[i++] = 0x09;
1490                 centrex[i++] = 0x02;
1491                 centrex[i++] = 0x01;
1492                 centrex[i++] = 0x0a;
1493         }
1494
1495         centrex[i++] = 0x80;
1496         centrex[i++] = strlen((char *)cnip);
1497         UCPY((char *)(&centrex[i]), (char *)cnip);
1498         i += strlen((char *)cnip);
1499         add_trace("facility", "cnip", "%s", cnip);
1500
1501         /* encode facility */
1502         enc_ie_facility(ntmode, msg, centrex, i);
1503 }
1504
1505 void Pdss1::dec_facility_centrex(unsigned char *p, Q931_info_t *qi, unsigned char *cnip, int cnip_len)
1506 {
1507         unsigned char centrex[256];
1508         char debug[768];
1509         int facility_len = 0;
1510         int i = 0, j;
1511         *cnip = '\0';
1512
1513         dec_ie_facility(p, qi, centrex, &facility_len);
1514         if (facility_len >= 2)
1515         {
1516                 if (centrex[i++] != CENTREX_FAC)
1517                         return;
1518                 if (centrex[i++] != CENTREX_ID)
1519                         return;
1520         }
1521
1522         /* loop sub IEs of facility */
1523         while(facility_len > i+1)
1524         {
1525                 if (centrex[i+1]+i+1 > facility_len)
1526                 {
1527                         PERROR("short read of centrex facility.\n");
1528                         return;
1529                 }
1530                 switch(centrex[i])
1531                 {
1532                         case 0x80:
1533                         strnncpy(cnip, &centrex[i+2], centrex[i+1], cnip_len);
1534                         add_trace("facility", "cnip", "%s", cnip);
1535                         break;
1536
1537                         default:
1538                         j = 0;
1539                         while(j < centrex[i+1])
1540                         {
1541                                 UPRINT(debug+(j*3), " %02x", centrex[i+1+j]);
1542                                 i++;
1543                         }
1544                         add_trace("facility", "CENTREX", "unknown=0x%02x len=%d%s\n", centrex[i], centrex[i+1], debug);
1545                 }
1546                 i += 1+centrex[i+1];
1547         }
1548 }
1549
1550
1551 /* IE_USERUSER */
1552 void Pdss1::enc_ie_useruser(unsigned char **ntmode, msg_t *msg, int protocol, unsigned char *user, int user_len)
1553 {
1554         unsigned char *p;
1555         Q931_info_t *qi = (Q931_info_t *)(msg->data + mISDN_HEADER_LEN);
1556         int l;
1557
1558         char buffer[768];
1559         int i;
1560
1561         if (protocol<0 || protocol>127)
1562         {
1563                 PERROR("protocol(%d) is out of range.\n", protocol);
1564                 return;
1565         }
1566         if (!user || user_len<=0)
1567         {
1568                 return;
1569         }
1570
1571         i = 0;
1572         while(i < user_len)
1573         {
1574                 UPRINT(buffer+(i*3), " %02x", user[i]);
1575                 i++;
1576         }
1577                 
1578         add_trace("useruser", "protocol", "%d", protocol);
1579         add_trace("useruser", "value", "%s", buffer);
1580
1581         l = user_len;
1582         p = msg_put(msg, l+3);
1583         if (p_m_d_ntmode)
1584                 *ntmode = p+1;
1585         else
1586                 qi->useruser.off = p - (unsigned char *)qi - sizeof(Q931_info_t);
1587         p[0] = IE_USER_USER;
1588         p[1] = l;
1589         p[2] = 0x80 + protocol;
1590         memcpy(p+3, user, user_len);
1591 }
1592
1593 void Pdss1::dec_ie_useruser(unsigned char *p, Q931_info_t *qi, int *protocol, unsigned char *user, int *user_len)
1594 {
1595         char buffer[768];
1596         int i;
1597
1598         *user_len = 0;
1599         *protocol = -1;
1600
1601         if (!p_m_d_ntmode)
1602         {
1603                 p = NULL;
1604                 if (qi->useruser.off)
1605                         p = (unsigned char *)qi + sizeof(Q931_info_t) + qi->useruser.off + 1;
1606         }
1607         if (!p)
1608                 return;
1609
1610         *user_len = p[0]-1;
1611         if (p[0] < 1)
1612                 return;
1613         *protocol = p[1];
1614         memcpy(user, p+2, (*user_len<=128)?*(user_len):128); /* clip to 128 maximum */
1615
1616         i = 0;
1617         while(i < *user_len)
1618         {
1619                 UPRINT(buffer+(i*3), " %02x", user[i]);
1620                 i++;
1621         }
1622         buffer[i*3] = '\0';
1623                 
1624         add_trace("useruser", "protocol", "%d", *protocol);
1625         add_trace("useruser", "value", "%s", buffer);
1626 }
1627
1628