fixed multiplexing bug at NT-mode.
[lcr.git] / joinpbx.cpp
1 /*****************************************************************************\
2 **                                                                           **
3 ** Linux Call Router                                                         **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** join functions                                                            **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <poll.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include "main.h"
21 #define __u8 unsigned char
22 #define __u16 unsigned short
23 #define __u32 unsigned long
24 #include "linux/isdnif.h"
25
26
27 /* notify endpoint about state change (if any) */
28 static int notify_state_change(int join_id, int epoint_id, int old_state, int new_state)
29 {
30         int notify_off = 0, notify_on = 0;
31         struct message *message;
32
33         if (old_state == new_state)
34                 return(old_state);
35
36         switch(old_state)
37         {
38                 case NOTIFY_STATE_ACTIVE:
39                 switch(new_state)
40                 {
41                         case NOTIFY_STATE_HOLD:
42                         notify_on = INFO_NOTIFY_REMOTE_HOLD;
43                         break;
44                         case NOTIFY_STATE_SUSPEND:
45                         notify_on = INFO_NOTIFY_USER_SUSPENDED;
46                         break;
47                         case NOTIFY_STATE_CONFERENCE:
48                         notify_on = INFO_NOTIFY_CONFERENCE_ESTABLISHED;
49                         break;
50                 }
51                 break;
52
53                 case NOTIFY_STATE_HOLD:
54                 switch(new_state)
55                 {
56                         case NOTIFY_STATE_ACTIVE:
57                         notify_off = INFO_NOTIFY_REMOTE_RETRIEVAL;
58                         break;
59                         case NOTIFY_STATE_SUSPEND:
60                         notify_off = INFO_NOTIFY_REMOTE_RETRIEVAL;
61                         notify_on = INFO_NOTIFY_USER_SUSPENDED;
62                         break;
63                         case NOTIFY_STATE_CONFERENCE:
64                         notify_off = INFO_NOTIFY_REMOTE_RETRIEVAL;
65                         notify_on = INFO_NOTIFY_CONFERENCE_ESTABLISHED;
66                         break;
67                 }
68                 break;
69
70                 case NOTIFY_STATE_SUSPEND:
71                 switch(new_state)
72                 {
73                         case NOTIFY_STATE_ACTIVE:
74                         notify_off = INFO_NOTIFY_USER_RESUMED;
75                         break;
76                         case NOTIFY_STATE_HOLD:
77                         notify_off = INFO_NOTIFY_USER_RESUMED;
78                         notify_on = INFO_NOTIFY_REMOTE_HOLD;
79                         break;
80                         case NOTIFY_STATE_CONFERENCE:
81                         notify_off = INFO_NOTIFY_USER_RESUMED;
82                         notify_on = INFO_NOTIFY_CONFERENCE_ESTABLISHED;
83                         break;
84                 }
85                 break;
86
87                 case NOTIFY_STATE_CONFERENCE:
88                 switch(new_state)
89                 {
90                         case NOTIFY_STATE_ACTIVE:
91                         notify_off = INFO_NOTIFY_CONFERENCE_DISCONNECTED;
92                         break;
93                         case NOTIFY_STATE_HOLD:
94                         notify_off = INFO_NOTIFY_CONFERENCE_DISCONNECTED;
95                         notify_on = INFO_NOTIFY_REMOTE_HOLD;
96                         break;
97                         case NOTIFY_STATE_SUSPEND:
98                         notify_off = INFO_NOTIFY_CONFERENCE_DISCONNECTED;
99                         notify_on = INFO_NOTIFY_USER_SUSPENDED;
100                         break;
101                 }
102                 break;
103         }
104
105         if (join_id && notify_off)
106         {
107                 message = message_create(join_id, epoint_id, JOIN_TO_EPOINT, MESSAGE_NOTIFY);
108                 message->param.notifyinfo.notify = notify_off;
109                 message_put(message);
110         }
111
112         if (join_id && notify_on)
113         {
114                 message = message_create(join_id, epoint_id, JOIN_TO_EPOINT, MESSAGE_NOTIFY);
115                 message->param.notifyinfo.notify = notify_on;
116                 message_put(message);
117         }
118
119         return(new_state);
120 }
121
122
123 /* debug function for join */
124 void joinpbx_debug(class JoinPBX *joinpbx, char *function)
125 {
126         struct join_relation *relation;
127         struct port_list *portlist;
128         class Endpoint *epoint;
129         class Port *port;
130         char buffer[512];
131
132         if (!(options.deb & DEBUG_JOIN))
133                 return;
134
135         PDEBUG(DEBUG_JOIN, "join(%d) start (called from %s)\n", joinpbx->j_serial, function);
136
137         relation = joinpbx->j_relation;
138
139         if (!relation)
140                 PDEBUG(DEBUG_JOIN, "join has no relations\n");
141         while(relation)
142         {
143                 epoint = find_epoint_id(relation->epoint_id);
144                 if (!epoint)
145                 {
146                         PDEBUG(DEBUG_JOIN, "warning: relations epoint id=%ld doesn't exists!\n", relation->epoint_id);
147                         relation = relation->next;
148                         continue;
149                 }
150                 buffer[0] = '\0';
151                 UPRINT(strchr(buffer,0), "*** ep%ld", relation->epoint_id);
152                 UPRINT(strchr(buffer,0), " ifs=");
153                 portlist = epoint->ep_portlist;
154                 while(portlist)
155                 {
156                         port = find_port_id(portlist->port_id);
157                         if (port)
158                                 UPRINT(strchr(buffer,0), "%s,", port->p_name);
159                         else
160                                 UPRINT(strchr(buffer,0), "<port %ld doesn't exist>,", portlist->port_id);
161                         portlist = portlist->next;
162                 }
163 //              UPRINT(strchr(buffer,0), " endpoint=%d on=%s hold=%s", epoint->ep_serial, (epoint->ep_join_id==joinpbx->j_serial)?"yes":"no", (epoint->get_hold_id()==joinpbx->j_serial)?"yes":"no");
164                 UPRINT(strchr(buffer,0), " endpoint=%d on=%s", epoint->ep_serial, (epoint->ep_join_id==joinpbx->j_serial)?"yes":"no");
165                 switch(relation->type)
166                 {
167                         case RELATION_TYPE_CALLING:
168                         UPRINT(strchr(buffer,0), " type=CALLING");
169                         break;
170                         case RELATION_TYPE_SETUP:
171                         UPRINT(strchr(buffer,0), " type=SETUP");
172                         break;
173                         case RELATION_TYPE_CONNECT:
174                         UPRINT(strchr(buffer,0), " type=CONNECT");
175                         break;
176                         default:
177                         UPRINT(strchr(buffer,0), " type=unknown");
178                         break;
179                 }
180                 switch(relation->channel_state)
181                 {
182                         case CHANNEL_STATE_CONNECT:
183                         UPRINT(strchr(buffer,0), " channel=CONNECT");
184                         break;
185                         case CHANNEL_STATE_HOLD:
186                         UPRINT(strchr(buffer,0), " channel=HOLD");
187                         break;
188                         default:
189                         UPRINT(strchr(buffer,0), " channel=unknown");
190                         break;
191                 }
192                 switch(relation->tx_state)
193                 {
194                         case NOTIFY_STATE_ACTIVE:
195                         UPRINT(strchr(buffer,0), " tx_state=ACTIVE");
196                         break;
197                         case NOTIFY_STATE_HOLD:
198                         UPRINT(strchr(buffer,0), " tx_state=HOLD");
199                         break;
200                         case NOTIFY_STATE_SUSPEND:
201                         UPRINT(strchr(buffer,0), " tx_state=SUSPEND");
202                         break;
203                         case NOTIFY_STATE_CONFERENCE:
204                         UPRINT(strchr(buffer,0), " tx_state=CONFERENCE");
205                         break;
206                         default:
207                         UPRINT(strchr(buffer,0), " tx_state=unknown");
208                         break;
209                 }
210                 switch(relation->rx_state)
211                 {
212                         case NOTIFY_STATE_ACTIVE:
213                         UPRINT(strchr(buffer,0), " rx_state=ACTIVE");
214                         break;
215                         case NOTIFY_STATE_HOLD:
216                         UPRINT(strchr(buffer,0), " rx_state=HOLD");
217                         break;
218                         case NOTIFY_STATE_SUSPEND:
219                         UPRINT(strchr(buffer,0), " rx_state=SUSPEND");
220                         break;
221                         case NOTIFY_STATE_CONFERENCE:
222                         UPRINT(strchr(buffer,0), " rx_state=CONFERENCE");
223                         break;
224                         default:
225                         UPRINT(strchr(buffer,0), " rx_state=unknown");
226                         break;
227                 }
228                 PDEBUG(DEBUG_JOIN, "%s\n", buffer);
229                 relation = relation->next;
230         }
231
232         PDEBUG(DEBUG_JOIN, "end\n");
233 }
234
235
236 /*
237  * constructor for a new join 
238  * the join will have a relation to the calling endpoint
239  */
240 JoinPBX::JoinPBX(class Endpoint *epoint) : Join()
241 {
242         struct join_relation *relation;
243 //      char filename[256];
244
245         if (!epoint)
246                 FATAL("epoint is NULL.\n");
247
248         PDEBUG(DEBUG_JOIN, "creating new join and connecting it to the endpoint.\n");
249
250         j_type = JOIN_TYPE_PBX;
251         j_caller[0] = '\0';
252         j_caller_id[0] = '\0';
253         j_dialed[0] = '\0';
254         j_todial[0] = '\0';
255         j_pid = getpid();
256         j_updatebridge = 0;
257         j_partyline = 0;
258         j_partyline_jingle = 0;
259         j_multicause = 0;
260         j_multilocation = 0;
261
262         /* initialize a relation only to the calling interface */
263         relation = j_relation = (struct join_relation *)MALLOC(sizeof(struct join_relation));
264         cmemuse++;
265         relation->type = RELATION_TYPE_CALLING;
266         relation->channel_state = CHANNEL_STATE_HOLD; /* audio is assumed on a new join */
267         relation->tx_state = NOTIFY_STATE_ACTIVE; /* new joins always assumed to be active */
268         relation->rx_state = NOTIFY_STATE_ACTIVE; /* new joins always assumed to be active */
269         relation->epoint_id = epoint->ep_serial;
270
271
272         if (options.deb & DEBUG_JOIN)
273                 joinpbx_debug(this, "JoinPBX::Constructor(new join)");
274 }
275
276
277 /*
278  * join descructor
279  */
280 JoinPBX::~JoinPBX()
281 {
282         struct join_relation *relation, *rtemp;
283
284         relation = j_relation;
285         while(relation)
286         {
287                 rtemp = relation->next;
288                 FREE(relation, sizeof(struct join_relation));
289                 cmemuse--;
290                 relation = rtemp;
291         }
292 }
293
294
295 /* bridge sets the audio flow of all bchannels assiociated to 'this' join
296  * also it changes and notifies active/hold/conference states
297  */
298 void JoinPBX::bridge(void)
299 {
300         struct join_relation *relation;
301         struct message *message;
302         int numconnect = 0, relations = 0;
303         class Endpoint *epoint;
304         struct port_list *portlist;
305         class Port *port;
306 #ifdef DEBUG_COREBRIDGE
307         int allmISDN = 0; // never set for debug purpose
308 #else
309         int allmISDN = 1; // set until a non-mISDN relation is found
310 #endif
311
312         relation = j_relation;
313         while(relation)
314         {
315                 /* count all relations */
316                 relations++;
317
318                 /* check for relation's objects */
319                 epoint = find_epoint_id(relation->epoint_id);
320                 if (!epoint)
321                 {
322                         PERROR("software error: relation without existing endpoints.\n");
323                         relation = relation->next;
324                         continue;
325                 }
326                 portlist = epoint->ep_portlist;
327                 if (!portlist)
328                 {
329                         PDEBUG(DEBUG_JOIN, "join%d ignoring relation without port object.\n", j_serial);
330 //#warning testing: keep on hold until single audio stream available
331                         relation->channel_state = CHANNEL_STATE_HOLD;
332                         relation = relation->next;
333                         continue;
334                 }
335                 if (portlist->next)
336                 {
337                         PDEBUG(DEBUG_JOIN, "join%d ignoring relation with ep%d due to port_list.\n", j_serial, epoint->ep_serial);
338 //#warning testing: keep on hold until single audio stream available
339                         relation->channel_state = CHANNEL_STATE_HOLD;
340                         relation = relation->next;
341                         continue;
342                 }
343                 port = find_port_id(portlist->port_id);
344                 if (!port)
345                 {
346                         PDEBUG(DEBUG_JOIN, "join%d ignoring relation without existing port object.\n", j_serial);
347                         relation = relation->next;
348                         continue;
349                 }
350                 if ((port->p_type&PORT_CLASS_MASK)!=PORT_CLASS_mISDN)
351                 {
352                         PDEBUG(DEBUG_JOIN, "join%d ignoring relation ep%d because it's port is not mISDN.\n", j_serial, epoint->ep_serial);
353                         if (allmISDN)
354                         {
355                                 PDEBUG(DEBUG_JOIN, "join%d not all endpoints are mISDN.\n", j_serial);
356                                 allmISDN = 0;
357                         }
358                         relation = relation->next;
359                         continue;
360                 }
361                 
362                 relation = relation->next;
363         }
364
365         PDEBUG(DEBUG_JOIN, "join%d members=%d %s\n", j_serial, relations, (allmISDN)?"(all are mISDN-members)":"(not all are mISDN-members)");
366         /* we notify all relations about rxdata. */
367         relation = j_relation;
368         while(relation)
369         {
370                 /* count connected relations */
371                 if ((relation->channel_state == CHANNEL_STATE_CONNECT)
372                  && (relation->rx_state != NOTIFY_STATE_SUSPEND)
373                  && (relation->rx_state != NOTIFY_STATE_HOLD))
374                         numconnect ++;
375
376                 /* remove unconnected parties from conference, also remove remotely disconnected parties so conference will not be disturbed. */
377                 if (relation->channel_state == CHANNEL_STATE_CONNECT
378                  && relation->rx_state != NOTIFY_STATE_HOLD
379                  && relation->rx_state != NOTIFY_STATE_SUSPEND
380                  && relations>1 // no conf with one member
381                  && allmISDN) // no conf if any member is not mISDN
382                 {
383                         message = message_create(j_serial, relation->epoint_id, JOIN_TO_EPOINT, MESSAGE_mISDNSIGNAL);
384                         message->param.mISDNsignal.message = mISDNSIGNAL_CONF;
385                         message->param.mISDNsignal.conf = j_serial<<16 | j_pid;
386                         PDEBUG(DEBUG_JOIN, "join%d EP%d +on+ id: 0x%08x\n", j_serial, relation->epoint_id, message->param.mISDNsignal.conf);
387                         message_put(message);
388                 } else
389                 {
390                         message = message_create(j_serial, relation->epoint_id, JOIN_TO_EPOINT, MESSAGE_mISDNSIGNAL);
391                         message->param.mISDNsignal.message = mISDNSIGNAL_CONF;
392                         message->param.mISDNsignal.conf = 0;
393                         PDEBUG(DEBUG_JOIN, "join%d EP%d +off+ id: 0x%08x\n", j_serial, relation->epoint_id, message->param.mISDNsignal.conf);
394                         message_put(message);
395                 }
396
397                 /*
398                  * request data from endpoint/port if:
399                  * - two relations
400                  * - any without mISDN
401                  * in this case we bridge
402                  */
403                 message = message_create(j_serial, relation->epoint_id, JOIN_TO_EPOINT, MESSAGE_mISDNSIGNAL);
404                 message->param.mISDNsignal.message = mISDNSIGNAL_JOINDATA;
405                 message->param.mISDNsignal.joindata = (relations==2 && !allmISDN);
406                 PDEBUG(DEBUG_JOIN, "join%d EP%d set joindata=%d\n", j_serial, relation->epoint_id, message->param.mISDNsignal.joindata);
407                 message_put(message);
408
409                 relation = relation->next;
410         }
411
412         /* two people just exchange their states */
413         if (relations==2 && !j_partyline)
414         {
415                 PDEBUG(DEBUG_JOIN, "join%d 2 relations / no partyline\n", j_serial);
416                 relation = j_relation;
417                 relation->tx_state = notify_state_change(j_serial, relation->epoint_id, relation->tx_state, relation->next->rx_state);
418                 relation->next->tx_state = notify_state_change(j_serial, relation->next->epoint_id, relation->next->tx_state, relation->rx_state);
419         } else
420         /* one member in a join, so we put her on hold */
421         if ((relations==1 || numconnect==1) && !j_partyline_jingle)
422         {
423                 PDEBUG(DEBUG_JOIN, "join%d 1 member or only 1 connected, put on hold\n");
424                 relation = j_relation;
425                 while(relation)
426                 {
427                         if ((relation->channel_state == CHANNEL_STATE_CONNECT)
428                          && (relation->rx_state != NOTIFY_STATE_SUSPEND)
429                          && (relation->rx_state != NOTIFY_STATE_HOLD))
430                                 relation->tx_state = notify_state_change(j_serial, relation->epoint_id, relation->tx_state, NOTIFY_STATE_HOLD);
431                         relation = relation->next;
432                 }
433         } else
434         /* if conference/partyline (or more than two members and more than one is connected), so we set conference state */ 
435         {
436                 PDEBUG(DEBUG_JOIN, "join%d %d members, %d connected, signal conference\n", relations, numconnect);
437                 relation = j_relation;
438                 while(relation)
439                 {
440                         if ((relation->channel_state == CHANNEL_STATE_CONNECT)
441                          && (relation->rx_state != NOTIFY_STATE_SUSPEND)
442                          && (relation->rx_state != NOTIFY_STATE_HOLD))
443                                 relation->tx_state = notify_state_change(j_serial, relation->epoint_id, relation->tx_state, NOTIFY_STATE_CONFERENCE);
444                         relation = relation->next;
445                 }
446         }
447 }
448
449 /*
450  * bridging is only possible with two connected endpoints
451  */
452 void JoinPBX::bridge_data(unsigned long epoint_from, struct join_relation *relation_from, union parameter *param)
453 {
454         struct join_relation *relation_to;
455
456         /* if we are alone */
457         if (!j_relation->next)
458                 return;
459
460         /* if we are more than two */
461         if (j_relation->next->next)
462                 return;
463
464         /* skip if source endpoint has NOT audio mode CONNECT */
465         if (relation_from->channel_state != CHANNEL_STATE_CONNECT)
466                 return;
467
468         /* get destination relation */
469         relation_to = j_relation;
470         if (relation_to == relation_from)
471         {
472                 /* oops, we are the first, so destination is: */
473                 relation_to = relation_to->next;
474         }
475
476         /* skip if destination endpoint has NOT audio mode CONNECT */
477         if (relation_to->channel_state != CHANNEL_STATE_CONNECT)
478                 return;
479
480         /* now we may send our data to the endpoint where it
481          * will be delivered to the port
482          */
483 //printf("from %d, to %d\n", relation_from->epoint_id, relation_to->epoint_id);
484         message_forward(j_serial, relation_to->epoint_id, JOIN_TO_EPOINT, param);
485 }
486
487 /* release join from endpoint
488  * if the join has two relations, all relations are freed and the join will be
489  * destroyed
490  * on outgoing relations, the cause is collected, if not connected
491  * returns if join has been destroyed
492  */
493 int JoinPBX::release(struct join_relation *relation, int location, int cause)
494 {
495         struct join_relation *reltemp, **relationpointer;
496         struct message *message;
497         class Join *join;
498         int destroy = 0;
499
500         /* remove from bridge */
501         if (relation->channel_state != CHANNEL_STATE_HOLD)
502         {
503                 relation->channel_state = CHANNEL_STATE_HOLD;
504                 j_updatebridge = 1; /* update bridge flag */
505                 // note: if join is not released, bridge must be updated
506         }
507
508         /* detach given interface */
509         reltemp = j_relation;
510         relationpointer = &j_relation;
511         while(reltemp)
512         {
513                 /* endpoint of function call */
514                 if (relation == reltemp)
515                         break;
516                 relationpointer = &reltemp->next;
517                 reltemp = reltemp->next;
518         }
519         if (!reltemp)
520                 FATAL("relation not in list of our relations. this must not happen.\n");
521 //printf("releasing relation %d\n", reltemp->epoint_id);
522         *relationpointer = reltemp->next;
523         FREE(reltemp, sizeof(struct join_relation));
524         cmemuse--;
525         relation = reltemp = NULL; // just in case of reuse fault;
526
527         /* if no more relation */
528         if (!j_relation)
529         {
530                 PDEBUG(DEBUG_JOIN, "join is completely removed.\n");
531                 /* there is no more endpoint related to the join */
532                 destroy = 1;
533                 delete this;
534                 // end of join object!
535                 PDEBUG(DEBUG_JOIN, "join completely removed!\n");
536         } else
537         /* if join is a party line */
538         if (j_partyline)
539         {
540                 PDEBUG(DEBUG_JOIN, "join is a conference room, so we keep it alive until the last party left.\n");
541         } else
542         /* if only one relation left */
543         if (!j_relation->next)
544         {
545                 PDEBUG(DEBUG_JOIN, "join has one relation left, so we send it a release with the given cause %d.\n", cause);
546                 message = message_create(j_serial, j_relation->epoint_id, JOIN_TO_EPOINT, MESSAGE_RELEASE);
547                 message->param.disconnectinfo.cause = cause;
548                 message->param.disconnectinfo.location = location;
549                 message_put(message);
550                 destroy = 1;
551                 delete this;
552                 // end of join object!
553                 PDEBUG(DEBUG_JOIN, "join completely removed!\n");
554         }
555
556         join = join_first;
557         while(join)
558         {
559                 if (options.deb & DEBUG_JOIN && join->j_type==JOIN_TYPE_PBX)
560                         joinpbx_debug((class JoinPBX *)join, "join_release{all joins left}");
561                 join = join->next;
562         }
563         PDEBUG(DEBUG_JOIN, "join_release(): ended.\n");
564         return(destroy);
565 }
566
567 /* count number of relations in a join
568  */
569 int joinpbx_countrelations(unsigned long join_id)
570 {
571         struct join_relation *relation;
572         int i;
573         class Join *join;
574         class JoinPBX *joinpbx;
575
576         join = find_join_id(join_id);
577
578         if (!join)
579                 return(0);
580
581         if (join->j_type != JOIN_TYPE_REMOTE)
582                 return(2);
583
584         if (join->j_type != JOIN_TYPE_PBX)
585                 return(0);
586         joinpbx = (class JoinPBX *)join;
587
588         i = 0;
589         relation = joinpbx->j_relation;
590         while(relation)
591         {
592                 i++;
593                 relation = relation->next;
594         }
595
596         return(i);
597 }
598
599 void JoinPBX::remove_relation(struct join_relation *relation)
600 {
601         struct join_relation *temp, **tempp;
602
603         if (!relation)
604                 return;
605
606         temp = j_relation;
607         tempp = &j_relation;
608         while(temp)
609         {
610                 if (temp == relation)
611                         break;
612                 tempp = &temp->next;
613                 temp = temp->next;
614         }
615         if (!temp)
616         {
617                 PERROR("relation not in join.\n");
618                 return;
619         }
620
621         PDEBUG(DEBUG_JOIN, "removing relation.\n");
622         *tempp = relation->next;
623         FREE(temp, sizeof(struct join_relation));
624         cmemuse--;
625 }       
626
627
628 struct join_relation *JoinPBX::add_relation(void)
629 {
630         struct join_relation *relation;
631
632         if (!j_relation)
633         {
634                 PERROR("there is no first relation to this join\n");
635                 return(NULL);
636         }
637         relation = j_relation;
638         while(relation->next)
639                 relation = relation->next;
640
641         relation->next = (struct join_relation *)MALLOC(sizeof(struct join_relation));
642         cmemuse++;
643         /* the record pointer is set at the first time the data is received for the relation */
644
645 //      if (options.deb & DEBUG_JOIN)
646 //              joinpbx_debug(join, "add_relation");
647         return(relation->next);
648 }
649
650 /* epoint sends a message to a join
651  *
652  */
653 void JoinPBX::message_epoint(unsigned long epoint_id, int message_type, union parameter *param)
654 {
655         class Join *cl;
656         struct join_relation *relation, *reltemp;
657         int num;
658         int new_state;
659         struct message *message;
660 //      int size, writesize, oldpointer;
661         char *number, *numbers;
662
663         if (!epoint_id)
664         {
665                 PERROR("software error, epoint == NULL\n");
666                 return;
667         }
668
669 //      if (options.deb & DEBUG_JOIN)
670 //      {
671 //              PDEBUG(DEBUG_JOIN, "message %d received from ep%d.\n", message, epoint->ep_serial);
672 //              joinpbx_debug(join,"Join::message_epoint");
673 //      }
674         if (options.deb & DEBUG_JOIN)
675         {
676                 if (message_type != MESSAGE_DATA)
677                 {
678                         cl = join_first;
679                         while(cl)
680                         {
681                                 if (cl->j_type == JOIN_TYPE_PBX)
682                                         joinpbx_debug((class JoinPBX *)cl, "Join::message_epoint{all joins before processing}");
683                                 cl = cl->next;
684                         }
685                 }
686         }
687
688         /* check relation */
689         relation = j_relation;
690         while(relation)
691         {
692                 if (relation->epoint_id == epoint_id)
693                         break;
694                 relation = relation->next;
695         }
696         if (!relation)
697         {
698                 PDEBUG(DEBUG_JOIN, "no relation back to the endpoint found, ignoring (join=%d, endpoint=%d)\n", j_serial, epoint_id);
699                 return;
700         }
701
702         /* process party line */
703         if (message_type == MESSAGE_SETUP) if (param->setup.partyline && !j_partyline)
704         {
705                 j_partyline = param->setup.partyline;
706                 j_partyline_jingle = param->setup.partyline_jingle;
707         }
708         if (j_partyline)
709         {
710                 switch(message_type)
711                 {
712                         case MESSAGE_SETUP:
713                         PDEBUG(DEBUG_JOIN, "respsone with connect in partyline mode.\n");
714                         relation->type = RELATION_TYPE_CONNECT;
715                         message = message_create(j_serial, epoint_id, JOIN_TO_EPOINT, MESSAGE_CONNECT);
716                         SPRINT(message->param.connectinfo.id, "%d", j_partyline);
717                         message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
718                         message_put(message);
719                         j_updatebridge = 1; /* update bridge flag */
720                         if (j_partyline_jingle)
721                                play_jingle(1);
722                         break;
723                         
724                         case MESSAGE_AUDIOPATH:
725                         PDEBUG(DEBUG_JOIN, "join received channel message: %d.\n", param->audiopath);
726                         if (relation->channel_state != param->audiopath)
727                         {
728                                 relation->channel_state = param->audiopath;
729                                 j_updatebridge = 1; /* update bridge flag */
730                                 if (options.deb & DEBUG_JOIN)
731                                         joinpbx_debug(this, "Join::message_epoint{after setting new channel state}");
732                         }
733                         break;
734
735                         case MESSAGE_DISCONNECT:
736                         PDEBUG(DEBUG_JOIN, "releasing after receiving disconnect, because join in partyline mode.\n");
737                         message = message_create(j_serial, epoint_id, JOIN_TO_EPOINT, MESSAGE_RELEASE);
738                         message->param.disconnectinfo.cause = CAUSE_NORMAL;
739                         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
740                         message_put(message);
741                         // fall through
742
743                         case MESSAGE_RELEASE:
744                         PDEBUG(DEBUG_JOIN, "releasing from join\n");
745                         release(relation, 0, 0);
746                         if (j_relation && j_partyline_jingle)
747                                play_jingle(0);
748                         break;
749
750                         default:
751                         PDEBUG(DEBUG_JOIN, "ignoring message, because join in partyline mode.\n");
752                 }
753                 return;
754         }
755
756
757         /* process messages */
758         switch(message_type)
759         {
760                 /* process audio path message */
761                 case MESSAGE_AUDIOPATH:
762                 PDEBUG(DEBUG_JOIN, "join received channel message: %d.\n", param->audiopath);
763                 if (relation->channel_state != param->audiopath)
764                 {
765                         relation->channel_state = param->audiopath;
766                         j_updatebridge = 1; /* update bridge flag */
767                         if (options.deb & DEBUG_JOIN)
768                                 joinpbx_debug(this, "Join::message_epoint{after setting new channel state}");
769                 }
770                 return;
771
772                 /* track notify */
773                 case MESSAGE_NOTIFY:
774                 switch(param->notifyinfo.notify)
775                 {
776                         case INFO_NOTIFY_USER_SUSPENDED:
777                         case INFO_NOTIFY_USER_RESUMED:
778                         case INFO_NOTIFY_REMOTE_HOLD:
779                         case INFO_NOTIFY_REMOTE_RETRIEVAL:
780                         case INFO_NOTIFY_CONFERENCE_ESTABLISHED:
781                         case INFO_NOTIFY_CONFERENCE_DISCONNECTED:
782                         new_state = track_notify(relation->rx_state, param->notifyinfo.notify);
783                         if (new_state != relation->rx_state)
784                         {
785                                 relation->rx_state = new_state;
786                                 j_updatebridge = 1;
787                                 if (options.deb & DEBUG_JOIN)
788                                         joinpbx_debug(this, "Join::message_epoint{after setting new rx state}");
789                         }
790                         break;
791
792                         default:
793                         /* send notification to all other endpoints */
794                         reltemp = j_relation;
795                         while(reltemp)
796                         {
797                                 if (reltemp->epoint_id!=epoint_id && reltemp->epoint_id)
798                                 {
799                                         message = message_create(j_serial, reltemp->epoint_id, JOIN_TO_EPOINT, MESSAGE_NOTIFY);
800                                         memcpy(&message->param, param, sizeof(union parameter));
801                                         message_put(message);
802                                 }
803                                 reltemp = reltemp->next;
804                         }
805                 }
806                 return;
807
808                 /* audio data */
809                 case MESSAGE_DATA:
810                 /* now send audio data to the other endpoint */
811                 bridge_data(epoint_id, relation, param);
812                 return;
813
814                 /* relations sends a connect */
815                 case MESSAGE_CONNECT:
816                 /* outgoing setup type becomes connected */
817                 if (relation->type == RELATION_TYPE_SETUP)
818                         relation->type = RELATION_TYPE_CONNECT;
819                 /* release other relations in setup state */
820                 release_again:
821                 reltemp = j_relation;
822                 while(reltemp)
823                 {
824 //printf("connect, checking relation %d\n", reltemp->epoint_id);
825                         if (reltemp->type == RELATION_TYPE_SETUP)
826                         {
827 //printf("relation %d is of type setup, releasing\n", reltemp->epoint_id);
828                                 /* send release to endpoint */
829                                 message = message_create(j_serial, reltemp->epoint_id, JOIN_TO_EPOINT, MESSAGE_RELEASE);
830                                 message->param.disconnectinfo.cause = CAUSE_NONSELECTED;
831                                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
832                                 message_put(message);
833
834                                 if (release(reltemp, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL)) // dummy cause, should not be used, since calling and connected endpoint still exist afterwards.
835                                         return; // must return, because join IS destroyed
836                                 goto release_again;
837                         }
838                         if (reltemp->type == RELATION_TYPE_CALLING)
839                                 reltemp->type = RELATION_TYPE_CONNECT;
840                         reltemp = reltemp->next;
841                 }
842                 break; // continue with our message
843
844                 /* release is sent by endpoint */
845                 case MESSAGE_RELEASE:
846                 switch(relation->type)
847                 {
848                         case RELATION_TYPE_SETUP: /* by called */
849                         /* collect cause and send collected cause */
850                         collect_cause(&j_multicause, &j_multilocation, param->disconnectinfo.cause, param->disconnectinfo.location);
851                         if (j_multicause)
852                                 release(relation, j_multilocation, j_multicause);
853                         else
854                                 release(relation, LOCATION_PRIVATE_LOCAL, CAUSE_UNSPECIFIED);
855                         break;
856
857                         case RELATION_TYPE_CALLING: /* by calling */
858                         /* remove us, if we don't have a called releation yet */
859                         if (!j_relation->next)
860                         {
861                                 release(j_relation, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
862                                 return; // must return, because join IS destroyed
863                         }
864                         /* remove all relations that are in called */
865                         release_again2:
866                         reltemp = j_relation;
867                         while(reltemp)
868                         {
869                                 if (reltemp->type == RELATION_TYPE_SETUP)
870                                 {
871                                         /* send release to endpoint */
872                                         message = message_create(j_serial, reltemp->epoint_id, JOIN_TO_EPOINT, message_type);
873                                         memcpy(&message->param, param, sizeof(union parameter));
874                                         message_put(message);
875
876                                         if (release(reltemp, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL))
877                                                 return; // must return, because join IS destroyed
878                                         goto release_again2;
879                                 }
880                                 reltemp = reltemp->next;
881                         }
882                         PERROR("we are still here, this should not happen\n");
883                         break;
884
885                         default: /* by connected */
886                         /* send current cause */
887                         release(relation, param->disconnectinfo.location, param->disconnectinfo.cause);
888                 }
889                 return; // must return, because join may be destroyed
890         }
891
892         /* count relations */
893         num=joinpbx_countrelations(j_serial);
894
895         /* check number of relations */
896         if (num > 2)
897         {
898                 PDEBUG(DEBUG_JOIN, "join has more than two relations so there is no need to send a message.\n");
899                 return;
900         }
901
902         /* find interfaces not related to calling epoint */
903         relation = j_relation;
904         while(relation)
905         {
906                 if (relation->epoint_id != epoint_id)
907                         break;
908                 relation = relation->next;
909         }
910         if (!relation)
911         {
912                 switch(message_type)
913                 {
914                         case MESSAGE_SETUP:
915                         if (param->setup.dialinginfo.itype == INFO_ITYPE_ISDN_EXTENSION)
916                         {
917                                 numbers = param->setup.dialinginfo.id;
918                                 while((number = strsep(&numbers, ",")))
919                                 {
920                                         if (out_setup(epoint_id, message_type, param, number))
921                                                 return; // join destroyed
922                                 }
923                                 break;
924                         }
925                         if (out_setup(epoint_id, message_type, param, NULL))
926                                 return; // join destroyed
927                         break;
928
929                         default:
930                         PDEBUG(DEBUG_JOIN, "no need to send a message because there is no other endpoint than the calling one.\n");
931                 }
932         } else
933         {
934                 PDEBUG(DEBUG_JOIN, "sending message ep%ld -> ep%ld.\n", epoint_id, relation->epoint_id);
935                 message = message_create(j_serial, relation->epoint_id, JOIN_TO_EPOINT, message_type);
936                 memcpy(&message->param, param, sizeof(union parameter));
937                 message_put(message);
938                 PDEBUG(DEBUG_JOIN, "message sent.\n");
939         }
940 }
941
942
943 /* join process is called from the main loop
944  * it processes the current calling state.
945  * returns 0 if join nothing was done
946  */
947 int JoinPBX::handler(void)
948 {
949 //      struct join_relation *relation;
950 //      char dialing[32][32];
951 //      int port[32];
952 //      int found;
953 //      int i, j;
954 //      char *p;
955
956         /* the bridge must be updated */
957         if (j_updatebridge)
958         {
959                 bridge();
960                 j_updatebridge = 0;
961                 return(1);
962         }
963
964         return(0);
965 }
966
967
968 int track_notify(int oldstate, int notify)
969 {
970         int newstate = oldstate;
971
972         switch(notify)
973         {
974                 case INFO_NOTIFY_USER_RESUMED:
975                 case INFO_NOTIFY_REMOTE_RETRIEVAL:
976                 case INFO_NOTIFY_CONFERENCE_DISCONNECTED:
977                 case INFO_NOTIFY_RESERVED_CT_1:
978                 case INFO_NOTIFY_RESERVED_CT_2:
979                 case INFO_NOTIFY_CALL_IS_DIVERTING:
980                 newstate = NOTIFY_STATE_ACTIVE;
981                 break;
982
983                 case INFO_NOTIFY_USER_SUSPENDED:
984                 newstate = NOTIFY_STATE_SUSPEND;
985                 break;
986
987                 case INFO_NOTIFY_REMOTE_HOLD:
988                 newstate = NOTIFY_STATE_HOLD;
989                 break;
990
991                 case INFO_NOTIFY_CONFERENCE_ESTABLISHED:
992                 newstate = NOTIFY_STATE_CONFERENCE;
993                 break;
994         }
995
996         return(newstate);
997 }
998
999
1000 /*
1001  * setup to exactly one endpoint
1002  * if it fails, the calling endpoint is released.
1003  * if other outgoing endpoints already exists, they are release as well.
1004  * note: if this functions fails, it will destroy its own join object!
1005  */
1006 int JoinPBX::out_setup(unsigned long epoint_id, int message_type, union parameter *param, char *newnumber)
1007 {
1008         struct join_relation *relation;
1009         struct message *message;
1010         class Endpoint *epoint;
1011
1012         PDEBUG(DEBUG_JOIN, "no endpoint found, so we will create an endpoint and send the setup message we have.\n");
1013         /* create a new relation */
1014         if (!(relation=add_relation()))
1015                 FATAL("No memory for relation.\n");
1016         relation->type = RELATION_TYPE_SETUP;
1017         relation->channel_state = CHANNEL_STATE_HOLD; /* audio is assumed on a new join */
1018         relation->tx_state = NOTIFY_STATE_ACTIVE; /* new joins always assumed to be active */
1019         relation->rx_state = NOTIFY_STATE_ACTIVE; /* new joins always assumed to be active */
1020         /* create a new endpoint */
1021         epoint = new Endpoint(0, j_serial);
1022         if (!epoint)
1023                 FATAL("No memory for Endpoint instance\n");
1024         if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint)))
1025                 FATAL("No memory for Endpoint Application instance\n");
1026         relation->epoint_id = epoint->ep_serial;
1027         /* send setup message to new endpoint */
1028 //printf("JOLLY DEBUG: %d\n",join_countrelations(j_serial));
1029 //i                     if (options.deb & DEBUG_JOIN)
1030 //                              joinpbx_debug(join, "Join::message_epoint");
1031         message = message_create(j_serial, relation->epoint_id, JOIN_TO_EPOINT, message_type);
1032         memcpy(&message->param, param, sizeof(union parameter));
1033         if (newnumber)
1034                 SCPY(message->param.setup.dialinginfo.id, newnumber);
1035         PDEBUG(DEBUG_JOIN, "setup message sent to ep %d with number='%s'.\n", relation->epoint_id, message->param.setup.dialinginfo.id);
1036         message_put(message);
1037         return(0);
1038 }
1039
1040
1041 /* send play message to all members to play join/release jingle */
1042 void JoinPBX::play_jingle(int in)
1043 {
1044         struct join_relation *relation;
1045         struct message *message;
1046
1047         relation = j_relation;
1048         while(relation)
1049         {
1050                 message = message_create(j_serial, relation->epoint_id, JOIN_TO_EPOINT, MESSAGE_TONE);
1051                 SCPY(message->param.tone.name, (char *)((in)?"left":"joined"));
1052                 message_put(message);
1053                 relation = relation->next;
1054         }
1055 }
1056
1057