backup
[lcr.git] / callpbx.cpp
1 /*****************************************************************************\
2 **                                                                           **
3 ** PBX4Linux                                                                 **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** call 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 call_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 (call_id && notify_off)
106         {
107                 message = message_create(call_id, epoint_id, CALL_TO_EPOINT, MESSAGE_NOTIFY);
108                 message->param.notifyinfo.notify = notify_off;
109                 message_put(message);
110         }
111
112         if (call_id && notify_on)
113         {
114                 message = message_create(call_id, epoint_id, CALL_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 call */
124 void callpbx_debug(class CallPBX *callpbx, char *function)
125 {
126         struct call_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_CALL))
133                 return;
134
135         PDEBUG(DEBUG_CALL, "CALL(%d) start (called from %s)\n", callpbx->c_serial, function);
136
137         relation = callpbx->c_relation;
138
139         if (!relation)
140                 PDEBUG(DEBUG_CALL, "call has no relations\n");
141         while(relation)
142         {
143                 epoint = find_epoint_id(relation->epoint_id);
144                 if (!epoint)
145                 {
146                         PDEBUG(DEBUG_CALL, "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_call_id==callpbx->c_serial)?"yes":"no", (epoint->get_hold_id()==callpbx->c_serial)?"yes":"no");
164                 UPRINT(strchr(buffer,0), " endpoint=%d on=%s", epoint->ep_serial, (epoint->ep_call_id==callpbx->c_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_CALL, "%s\n", buffer);
229                 relation = relation->next;
230         }
231
232         PDEBUG(DEBUG_CALL, "end\n");
233 }
234
235
236 /*
237  * constructor for a new call 
238  * the call will have a relation to the calling endpoint
239  */
240 CallPBX::CallPBX(class Endpoint *epoint) : Call(epoint)
241 {
242         struct call_relation *relation;
243 //      char filename[256];
244
245         if (!epoint)
246         {
247                 PERROR("software error, epoint is NULL.\n");
248                 exit(-1);
249         }
250
251         PDEBUG(DEBUG_CALL, "creating new call and connecting it to the endpoint.\n");
252
253         c_type = CALL_TYPE_PBX;
254         c_caller[0] = '\0';
255         c_caller_id[0] = '\0';
256         c_dialed[0] = '\0';
257         c_todial[0] = '\0';
258         c_pid = getpid();
259         c_updatebridge = 0;
260         c_partyline = 0;
261
262         /* initialize a relation only to the calling interface */
263         relation = c_relation = (struct call_relation *)calloc(1, sizeof(struct call_relation));
264         if (!relation)
265         {
266                 PERROR("no memory, exitting..\n");
267                 exit(-1);
268         }
269         cmemuse++;
270         memset(relation, 0, sizeof(struct call_relation));
271         relation->type = RELATION_TYPE_CALLING;
272         relation->channel_state = CHANNEL_STATE_HOLD; /* audio is assumed on a new call */
273         relation->tx_state = NOTIFY_STATE_ACTIVE; /* new calls always assumed to be active */
274         relation->rx_state = NOTIFY_STATE_ACTIVE; /* new calls always assumed to be active */
275         relation->epoint_id = epoint->ep_serial;
276
277
278         if (options.deb & DEBUG_CALL)
279                 callpbx_debug(this, "CallPBX::Constructor(new call)");
280 }
281
282
283 /*
284  * call descructor
285  */
286 CallPBX::~CallPBX()
287 {
288         struct call_relation *relation, *rtemp;
289
290         relation = c_relation;
291         while(relation)
292         {
293                 rtemp = relation->next;
294                 memset(relation, 0, sizeof(struct call_relation));
295                 free(relation);
296                 cmemuse--;
297                 relation = rtemp;
298         }
299 }
300
301
302 /* bridge sets the audio flow of all bchannels assiociated to 'this' call
303  * also it changes and notifies active/hold/conference states
304  */
305 void CallPBX::bridge(void)
306 {
307         struct call_relation *relation;
308         struct message *message;
309         int numconnect = 0, relations = 0;
310         class Endpoint *epoint;
311         struct port_list *portlist;
312         class Port *port;
313         int allmISDN = 0; // set until a non-mISDN relation is found
314 fix:
315
316         relation = c_relation;
317         while(relation)
318         {
319                 /* count all relations */
320                 relations++;
321
322                 /* check for relation's objects */
323                 epoint = find_epoint_id(relation->epoint_id);
324                 if (!epoint)
325                 {
326                         PERROR("software error: relation without existing endpoints.\n");
327                         relation = relation->next;
328                         continue;
329                 }
330                 portlist = epoint->ep_portlist;
331                 if (!portlist)
332                 {
333                         PDEBUG(DEBUG_CALL, "CALL%d ignoring relation without port object.\n", c_serial);
334 //#warning testing: keep on hold until single audio stream available
335                         relation->channel_state = CHANNEL_STATE_HOLD;
336                         relation = relation->next;
337                         continue;
338                 }
339                 if (portlist->next)
340                 {
341                         PDEBUG(DEBUG_CALL, "CALL%d ignoring relation with ep%d due to port_list.\n", c_serial, epoint->ep_serial);
342 //#warning testing: keep on hold until single audio stream available
343                         relation->channel_state = CHANNEL_STATE_HOLD;
344                         relation = relation->next;
345                         continue;
346                 }
347                 port = find_port_id(portlist->port_id);
348                 if (!port)
349                 {
350                         PDEBUG(DEBUG_CALL, "CALL%d ignoring relation without existing port object.\n", c_serial);
351                         relation = relation->next;
352                         continue;
353                 }
354                 if ((port->p_type&PORT_CLASS_MASK)!=PORT_CLASS_mISDN)
355                 {
356                         PDEBUG(DEBUG_CALL, "CALL%d ignoring relation ep%d because it's port is not mISDN.\n", c_serial, epoint->ep_serial);
357                         if (allmISDN)
358                         {
359                                 PDEBUG(DEBUG_CALL, "CALL%d not all endpoints are mISDN.\n", c_serial);
360                                 allmISDN = 0;
361                         }
362                         relation = relation->next;
363                         continue;
364                 }
365                 
366                 relation = relation->next;
367         }
368
369         PDEBUG(DEBUG_CALL, "CALL%d members=%d %s\n", c_serial, relations, (allmISDN)?"(all are mISDN-members)":"(not all are mISDN-members)");
370         /* we notify all relations about rxdata. */
371         relation = c_relation;
372         while(relation)
373         {
374                 /* count connected relations */
375                 if ((relation->channel_state == CHANNEL_STATE_CONNECT)
376                  && (relation->rx_state != NOTIFY_STATE_SUSPEND)
377                  && (relation->rx_state != NOTIFY_STATE_HOLD))
378                         numconnect ++;
379
380                 /* remove unconnected parties from conference, also remove remotely disconnected parties so conference will not be disturbed. */
381                 if (relation->channel_state == CHANNEL_STATE_CONNECT
382                  && relation->rx_state != NOTIFY_STATE_HOLD
383                  && relation->rx_state != NOTIFY_STATE_SUSPEND
384                  && relations>1 // no conf with one member
385                  && allmISDN) // no conf if any member is not mISDN
386                 {
387                         message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, MESSAGE_mISDNSIGNAL);
388                         message->param.mISDNsignal.message = mISDNSIGNAL_CONF;
389                         message->param.mISDNsignal.conf = c_serial<<16 | c_pid;
390                         PDEBUG(DEBUG_CALL, "CALL%d EP%d +on+ id: 0x%08x\n", c_serial, relation->epoint_id, message->param.mISDNsignal.conf);
391                         message_put(message);
392                 } else
393                 {
394                         message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, MESSAGE_mISDNSIGNAL);
395                         message->param.mISDNsignal.message = mISDNSIGNAL_CONF;
396                         message->param.mISDNsignal.conf = 0;
397                         PDEBUG(DEBUG_CALL, "CALL%d EP%d +off+ id: 0x%08x\n", c_serial, relation->epoint_id, message->param.mISDNsignal.conf);
398                         message_put(message);
399                 }
400
401                 /*
402                  * request data from endpoint/port if:
403                  * - two relations
404                  * - any without mISDN
405                  * in this case we bridge
406                  */
407                 message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, MESSAGE_mISDNSIGNAL);
408                 message->param.mISDNsignal.message = mISDNSIGNAL_CALLDATA;
409                 message->param.mISDNsignal.calldata = (relations==2 && !allmISDN);
410                 PDEBUG(DEBUG_CALL, "CALL%d EP%d set calldata=%d\n", c_serial, relation->epoint_id, message->param.mISDNsignal.calldata);
411                 message_put(message);
412
413                 relation = relation->next;
414         }
415
416         /* two people just exchange their states */
417         if (relations==2 && !c_partyline)
418         {
419                 PDEBUG(DEBUG_CALL, "CALL%d 2 relations / no partyline\n", c_serial);
420                 relation = c_relation;
421                 relation->tx_state = notify_state_change(c_serial, relation->epoint_id, relation->tx_state, relation->next->rx_state);
422                 relation->next->tx_state = notify_state_change(c_serial, relation->next->epoint_id, relation->next->tx_state, relation->rx_state);
423         } else
424         /* one member in a call, so we put her on hold */
425         if (relations==1 || numconnect==1)
426         {
427                 PDEBUG(DEBUG_CALL, "CALL%d 1 member or only 1 connected, put on hold\n");
428                 relation = c_relation;
429                 while(relation)
430                 {
431                         if ((relation->channel_state == CHANNEL_STATE_CONNECT)
432                          && (relation->rx_state != NOTIFY_STATE_SUSPEND)
433                          && (relation->rx_state != NOTIFY_STATE_HOLD))
434                                 relation->tx_state = notify_state_change(c_serial, relation->epoint_id, relation->tx_state, NOTIFY_STATE_HOLD);
435                         relation = relation->next;
436                 }
437         } else
438         /* if conference/partyline or (more than two members and more than one is connected), so we set conference state */ 
439         {
440                 PDEBUG(DEBUG_CALL, "CALL%d %d members, %d connected, signal conference\n", relations, numconnect);
441                 relation = c_relation;
442                 while(relation)
443                 {
444                         if ((relation->channel_state == CHANNEL_STATE_CONNECT)
445                          && (relation->rx_state != NOTIFY_STATE_SUSPEND)
446                          && (relation->rx_state != NOTIFY_STATE_HOLD))
447                                 relation->tx_state = notify_state_change(c_serial, relation->epoint_id, relation->tx_state, NOTIFY_STATE_CONFERENCE);
448                         relation = relation->next;
449                 }
450         }
451 }
452
453 /*
454  * bridging is only possible with two connected endpoints
455  */
456 void CallPBX::bridge_data(unsigned long epoint_from, struct call_relation *relation_from, union parameter *param)
457 {
458         struct call_relation *relation_to;
459         struct message *message;
460
461         /* if we are alone */
462         if (!c_relation->next)
463                 return;
464
465         /* if we are more than two */
466         if (c_relation->next->next)
467                 return;
468
469         /* skip if source endpoint has NOT audio mode CONNECT */
470         if (relation_from->channel_state != CHANNEL_STATE_CONNECT)
471                 return;
472
473         /* get destination relation */
474         relation_to = c_relation;
475         if (relation_to == relation_from)
476         {
477                 /* oops, we are the first, so destination is: */
478                 relation_to = relation_to->next;
479         }
480
481         /* skip if destination endpoint has NOT audio mode CONNECT */
482         if (relation_to->channel_state != CHANNEL_STATE_CONNECT)
483                 return;
484
485         /* now we may send our data to the endpoint where it
486          * will be delivered to the port
487          */
488 //PDEBUG(DEBUG_CALL, "mixing from %d to %d\n", epoint_from, relation_to->epoint_id);
489 printf("from %d, to %d\n", relation_from->epoint_id, relation_to->epoint_id);
490         message = message_create(c_serial, relation_to->epoint_id, CALL_TO_EPOINT, MESSAGE_DATA);
491         memcpy(&message->param, param, sizeof(union parameter));
492         message_put(message);
493 }
494
495
496 /* release call from endpoint
497  * if the call has two relations, all relations are freed and the call will be
498  * destroyed 
499  */
500 void CallPBX::release(unsigned long epoint_id, int hold, int location, int cause)
501 {
502         struct call_relation *relation, **relationpointer;
503         struct message *message;
504
505         class Call *call;
506
507         if (!epoint_id)
508         {
509                 PERROR("software error, epoint is NULL.\n");
510                 return;
511         }
512
513         if (options.deb & DEBUG_CALL)
514                 callpbx_debug(this, "call_release{before}");
515
516         /* find relation */
517         relation = c_relation;
518         while(relation)
519         {
520                 if (relation->epoint_id == epoint_id)
521                         break;
522                 relation = relation->next;
523         }
524         if (!relation)
525         {
526                 PERROR("software error, epoint has a call with no relation to the epoint.\n");
527                 return;
528         }
529
530         /* remove from bridge */
531         if (relation->channel_state != CHANNEL_STATE_HOLD)
532         {
533                 relation->channel_state = CHANNEL_STATE_HOLD;
534                 c_updatebridge = 1; /* update bridge flag */
535         }
536
537         /* detach given interface */
538         relation = c_relation;
539         relationpointer = &c_relation;
540         while(relation)
541         {
542                 /* endpoint of function call */
543                 if (relation->epoint_id == epoint_id)
544                 {
545                         *relationpointer = relation->next;
546                         memset(relation, 0, sizeof(struct call_relation));
547                         free(relation);
548                         cmemuse--;
549                         relation = *relationpointer;
550                         continue;
551                 }
552                 relationpointer = &relation->next;
553                 relation = relation->next;
554         }
555
556         /* if no more relation */
557         if (!c_relation)
558         {
559                 PDEBUG(DEBUG_CALL, "call is completely removed.\n");
560                 /* there is no more endpoint related to the call */
561                 delete this;
562                 // end of call object!
563                 PDEBUG(DEBUG_CALL, "call completely removed!\n");
564         } else
565         /* if call is a party line */
566         if (c_partyline)
567         {
568                 PDEBUG(DEBUG_CALL, "call is a conference room, so we keep it alive until the last party left.\n");
569         } else
570         /* if only one relation left */
571         if (!c_relation->next)
572         {
573                 PDEBUG(DEBUG_CALL, "call has one relation left, so we send it a release with the given cause %d.\n", cause);
574                 message = message_create(c_serial, c_relation->epoint_id, CALL_TO_EPOINT, MESSAGE_RELEASE);
575                 message->param.disconnectinfo.cause = cause;
576                 message->param.disconnectinfo.location = location;
577                 message_put(message);
578                 delete this;
579                 // end of call object!
580                 PDEBUG(DEBUG_CALL, "call completely removed!\n");
581         }
582
583         call = call_first;
584         while(call)
585         {
586                 if (options.deb & DEBUG_CALL && call->c_type==CALL_TYPE_PBX)
587                         callpbx_debug((class CallPBX *)call, "call_release{all calls left}");
588                 call = call->next;
589         }
590         PDEBUG(DEBUG_CALL, "call_release(): ended.\n");
591 }
592
593 /* count number of relations in a call
594  */
595 int callpbx_countrelations(unsigned long call_id)
596 {
597         struct call_relation *relation;
598         int i;
599         class Call *call;
600         class CallPBX *callpbx;
601
602         call = find_call_id(call_id);
603
604         if (!call)
605                 return(0);
606
607         if (call->c_type != CALL_TYPE_ASTERISK)
608                 return(2);
609
610         if (call->c_type != CALL_TYPE_PBX)
611                 return(0);
612         callpbx = (class CallPBX *)call;
613
614         i = 0;
615         relation = callpbx->c_relation;
616         while(relation)
617         {
618                 i++;
619                 relation = relation->next;
620         }
621
622         return(i);
623 }
624
625 void CallPBX::remove_relation(struct call_relation *relation)
626 {
627         struct call_relation *temp, **tempp;
628
629         if (!relation)
630                 return;
631
632         temp = c_relation;
633         tempp = &c_relation;
634         while(temp)
635         {
636                 if (temp == relation)
637                         break;
638                 tempp = &temp->next;
639                 temp = temp->next;
640         }
641         if (!temp)
642         {
643                 PERROR("relation not in call.\n");
644                 return;
645         }
646
647         PDEBUG(DEBUG_CALL, "removing relation.\n");
648         *tempp = relation->next;
649         memset(temp, 0, sizeof(struct call_relation));
650         free(temp);
651         cmemuse--;
652 }       
653
654
655 struct call_relation *CallPBX::add_relation(void)
656 {
657         struct call_relation *relation;
658
659         if (!c_relation)
660         {
661                 PERROR("there is no first relation to this call\n");
662                 return(NULL);
663         }
664         relation = c_relation;
665         while(relation->next)
666                 relation = relation->next;
667
668         relation->next = (struct call_relation *)calloc(1, sizeof(struct call_relation));
669         if (!relation->next)
670         {
671                 PERROR("no memory\n");
672                 return(NULL);
673         }
674         cmemuse++;
675         memset(relation->next, 0, sizeof(struct call_relation));
676         /* the record pointer is set at the first time the data is received for the relation */
677
678 //      if (options.deb & DEBUG_CALL)
679 //              callpbx_debug(call, "add_relation");
680         return(relation->next);
681 }
682
683 /* epoint sends a message to a call
684  *
685  */
686 void CallPBX::message_epoint(unsigned long epoint_id, int message_type, union parameter *param)
687 {
688         class Call *cl;
689         struct call_relation *relation, *rel;
690         int num;
691         int new_state;
692         struct message *message;
693 //      int size, writesize, oldpointer;
694         char *number, *numbers;
695
696         if (!epoint_id)
697         {
698                 PERROR("software error, epoint == NULL\n");
699                 return;
700         }
701
702 //      if (options.deb & DEBUG_CALL)
703 //      {
704 //              PDEBUG(DEBUG_CALL, "message %d received from ep%d.\n", message, epoint->ep_serial);
705 //              callpbx_debug(call,"Call::message_epoint");
706 //      }
707         if (options.deb & DEBUG_CALL)
708         {
709                 if (message_type != MESSAGE_DATA)
710                 {
711                         cl = call_first;
712                         while(cl)
713                         {
714                                 if (cl->c_type == CALL_TYPE_PBX)
715                                         callpbx_debug((class CallPBX *)cl, "Call::message_epoint{all calls before processing}");
716                                 cl = cl->next;
717                         }
718                 }
719         }
720
721         /* check relation */
722         relation = c_relation;
723         while(relation)
724         {
725                 if (relation->epoint_id == epoint_id)
726                         break;
727                 relation = relation->next;
728         }
729         if (!relation)
730         {
731 //              PERROR("no relation back to the endpoint found, ignoring (call=%d, endpoint=%d\n", c_serial, epoint_id);
732                 return;
733         }
734
735         switch(message_type)
736         {
737                 /* process channel message */
738                 case MESSAGE_CHANNEL:
739                 PDEBUG(DEBUG_CALL, "call received channel message: %d.\n", param->channel);
740                 if (relation->channel_state != param->channel)
741                 {
742                         relation->channel_state = param->channel;
743                         c_updatebridge = 1; /* update bridge flag */
744                         if (options.deb & DEBUG_CALL)
745                                 callpbx_debug(this, "Call::message_epoint{after setting new channel state}");
746                 }
747                 return;
748
749                 /* track notify */
750                 case MESSAGE_NOTIFY:
751                 switch(param->notifyinfo.notify)
752                 {
753                         case INFO_NOTIFY_USER_SUSPENDED:
754                         case INFO_NOTIFY_USER_RESUMED:
755                         case INFO_NOTIFY_REMOTE_HOLD:
756                         case INFO_NOTIFY_REMOTE_RETRIEVAL:
757                         case INFO_NOTIFY_CONFERENCE_ESTABLISHED:
758                         case INFO_NOTIFY_CONFERENCE_DISCONNECTED:
759                         new_state = track_notify(relation->rx_state, param->notifyinfo.notify);
760                         if (new_state != relation->rx_state)
761                         {
762                                 relation->rx_state = new_state;
763                                 c_updatebridge = 1;
764                                 if (options.deb & DEBUG_CALL)
765                                         callpbx_debug(this, "Call::message_epoint{after setting new rx state}");
766                         }
767                         break;
768
769                         default:
770                         /* send notification to all other endpoints */
771                         rel = c_relation;
772                         while(rel)
773                         {
774                                 if (rel->epoint_id!=epoint_id && rel->epoint_id)
775                                 {
776                                         message = message_create(c_serial, rel->epoint_id, CALL_TO_EPOINT, MESSAGE_NOTIFY);
777                                         memcpy(&message->param, param, sizeof(union parameter));
778                                         message_put(message);
779                                 }
780                                 rel = rel->next;
781                         }
782                 }
783                 return;
784
785                 /* audio data */
786                 case MESSAGE_DATA:
787                 /* now send audio data to the other endpoint */
788                 bridge_data(epoint_id, relation, param);
789                 return;
790         }
791
792         /* process party line */
793         if (message_type == MESSAGE_SETUP) if (param->setup.partyline)
794         {
795                 PDEBUG(DEBUG_CALL, "respsone with connect in partyline mode.\n");
796                 c_partyline = param->setup.partyline;
797                 message = message_create(c_serial, epoint_id, CALL_TO_EPOINT, MESSAGE_CONNECT);
798                 message->param.setup.partyline = c_partyline;
799                 message_put(message);
800                 c_updatebridge = 1; /* update bridge flag */
801         }
802         if (c_partyline)
803         {
804                 if (message_type == MESSAGE_DISCONNECT)
805                 {
806                         PDEBUG(DEBUG_CALL, "releasing after receiving disconnect, because call in partyline mode.\n");
807 //                      remove_relation(relation);
808                         message = message_create(c_serial, epoint_id, CALL_TO_EPOINT, MESSAGE_RELEASE);
809                         message->param.disconnectinfo.cause = CAUSE_NORMAL;
810                         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
811                         message_put(message);
812 //                      c_updatebridge = 1; /* update bridge flag */
813                         return;
814                 }
815         }
816         if (c_partyline)
817         {
818                 PDEBUG(DEBUG_CALL, "ignoring message, because call in partyline mode.\n");
819                 return;
820         }
821
822         /* count relations */
823         num=callpbx_countrelations(c_serial);
824
825         /* check number of relations */
826         if (num > 2)
827         {
828                 PDEBUG(DEBUG_CALL, "call has more than two relations so there is no need to send a message.\n");
829                 return;
830         }
831
832         /* find interfaces not related to calling epoint */
833         relation = c_relation;
834         while(relation)
835         {
836                 if (relation->epoint_id != epoint_id)
837                         break;
838                 relation = relation->next;
839         }
840         if (!relation)
841         {
842                 switch(message_type)
843                 {
844                         case MESSAGE_SETUP:
845                         if (param->setup.dialinginfo.itype == INFO_ITYPE_ISDN_EXTENSION)
846                         {
847                                 numbers = param->setup.dialinginfo.id;
848                                 while((number = strsep(&numbers, ",")))
849                                 {
850                                         if (out_setup(epoint_id, message_type, param, number))
851                                                 return; // call destroyed
852                                 }
853                                 break;
854                         }
855                         if (out_setup(epoint_id, message_type, param, NULL))
856                                 return; // call destroyed
857                         break;
858
859                         default:
860                         PDEBUG(DEBUG_CALL, "no need to send a message because there is no other endpoint than the calling one.\n");
861                 }
862         } else
863         {
864                 PDEBUG(DEBUG_CALL, "sending message ep%ld -> ep%ld.\n", epoint_id, relation->epoint_id);
865                 message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, message_type);
866                 memcpy(&message->param, param, sizeof(union parameter));
867                 message_put(message);
868                 PDEBUG(DEBUG_CALL, "message sent.\n");
869         }
870 }
871
872
873 /* call process is called from the main loop
874  * it processes the current calling state.
875  * returns 0 if call nothing was done
876  */
877 int CallPBX::handler(void)
878 {
879 //      struct call_relation *relation;
880 //      char dialing[32][32];
881 //      int port[32];
882 //      int found;
883 //      int i, j;
884 //      char *p;
885
886         /* the bridge must be updated */
887         if (c_updatebridge)
888         {
889                 bridge();
890                 c_updatebridge = 0;
891                 return(1);
892         }
893
894         return(0);
895 }
896
897
898 int track_notify(int oldstate, int notify)
899 {
900         int newstate = oldstate;
901
902         switch(notify)
903         {
904                 case INFO_NOTIFY_USER_RESUMED:
905                 case INFO_NOTIFY_REMOTE_RETRIEVAL:
906                 case INFO_NOTIFY_CONFERENCE_DISCONNECTED:
907                 case INFO_NOTIFY_RESERVED_CT_1:
908                 case INFO_NOTIFY_RESERVED_CT_2:
909                 case INFO_NOTIFY_CALL_IS_DIVERTING:
910                 newstate = NOTIFY_STATE_ACTIVE;
911                 break;
912
913                 case INFO_NOTIFY_USER_SUSPENDED:
914                 newstate = NOTIFY_STATE_SUSPEND;
915                 break;
916
917                 case INFO_NOTIFY_REMOTE_HOLD:
918                 newstate = NOTIFY_STATE_HOLD;
919                 break;
920
921                 case INFO_NOTIFY_CONFERENCE_ESTABLISHED:
922                 newstate = NOTIFY_STATE_CONFERENCE;
923                 break;
924         }
925
926         return(newstate);
927 }
928
929
930 /*
931  * setup to exactly one endpoint
932  * if it fails, the calling endpoint is released.
933  * if other outgoing endpoints already exists, they are release as well.
934  * note: if this functions fails, it will destroy its own call object!
935  */
936 int CallPBX::out_setup(unsigned long epoint_id, int message_type, union parameter *param, char *newnumber)
937 {
938         struct call_relation *relation;
939         struct message *message;
940         class Endpoint *epoint;
941
942         PDEBUG(DEBUG_CALL, "no endpoint found, so we will create an endpoint and send the setup message we have.\n");
943         /* create a new relation */
944         if (!(relation=add_relation()))
945         {
946                 /* release due to error */
947                 ressource_error:
948                 relation = c_relation;
949                 while(relation)
950                 {
951                         message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, MESSAGE_RELEASE);
952                         message->param.disconnectinfo.cause = (relation->epoint_id==epoint_id)?CAUSE_RESSOURCEUNAVAIL:CAUSE_NORMAL; 
953                         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
954                         message_put(message);
955                         relation = relation->next;
956                 }
957                 delete this;
958                 return(-ENOMEM);
959         }
960         relation->type = RELATION_TYPE_SETUP;
961         relation->channel_state = CHANNEL_STATE_HOLD; /* audio is assumed on a new call */
962         relation->tx_state = NOTIFY_STATE_ACTIVE; /* new calls always assumed to be active */
963         relation->rx_state = NOTIFY_STATE_ACTIVE; /* new calls always assumed to be active */
964         /* create a new endpoint */
965         epoint = new Endpoint(0, c_serial);
966         if (!epoint)
967         {
968                 remove_relation(relation);
969                 goto ressource_error;
970         }
971         if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint)))
972         {
973                 PERROR("ERROR:No endpoint's app.\n");
974                 delete epoint;
975                 remove_relation(relation);
976                 goto ressource_error;
977         }
978         relation->epoint_id = epoint->ep_serial;
979         /* send setup message to new endpoint */
980 //printf("JOLLY DEBUG: %d\n",call_countrelations(c_serial));
981 //i                     if (options.deb & DEBUG_CALL)
982 //                              callpbx_debug(call, "Call::message_epoint");
983         message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, message_type);
984         memcpy(&message->param, param, sizeof(union parameter));
985         if (newnumber)
986                 SCPY(message->param.setup.dialinginfo.id, newnumber);
987         PDEBUG(DEBUG_CALL, "setup message sent to ep %d with number='%s'.\n", relation->epoint_id, message->param.setup.dialinginfo.id);
988         message_put(message);
989         return(0);
990 }
991