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