bb644d0bce92f05f34654d3eac9262f58f035efb
[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_mixer = 0;
259         c_partyline = 0;
260
261         /* initialize a relation only to the calling interface */
262         relation = c_relation = (struct call_relation *)calloc(1, sizeof(struct call_relation));
263         if (!relation)
264         {
265                 PERROR("no memory, exitting..\n");
266                 exit(-1);
267         }
268         cmemuse++;
269         memset(relation, 0, sizeof(struct call_relation));
270         relation->type = RELATION_TYPE_CALLING;
271         relation->channel_state = CHANNEL_STATE_HOLD; /* audio is assumed on a new call */
272         relation->tx_state = NOTIFY_STATE_ACTIVE; /* new calls always assumed to be active */
273         relation->rx_state = NOTIFY_STATE_ACTIVE; /* new calls always assumed to be active */
274         relation->epoint_id = epoint->ep_serial;
275
276
277         if (options.deb & DEBUG_CALL)
278                 callpbx_debug(this, "CallPBX::Constructor(new call)");
279 }
280
281
282 /*
283  * call descructor
284  */
285 CallPBX::~CallPBX()
286 {
287         struct call_relation *relation, *rtemp;
288
289         relation = c_relation;
290         while(relation)
291         {
292                 rtemp = relation->next;
293                 memset(relation, 0, sizeof(struct call_relation));
294                 free(relation);
295                 cmemuse--;
296                 relation = rtemp;
297         }
298 }
299
300
301 /* mixer sets the mixer of hisax bchannels
302  * the mixer() will set the mixer for the hisax ports which is done
303  * at kernel space. 
304  */
305 void CallPBX::mixer(void)
306 {
307         struct call_relation *relation;
308         struct message *message;
309         int numconnect, relations;
310         class Endpoint *epoint;
311         struct port_list *portlist;
312         class Port *port;
313         int nodata = 1;
314
315         relation = c_relation;
316         while(relation)
317         {
318                 epoint = find_epoint_id(relation->epoint_id);
319                 if (!epoint)
320                 {
321                         PERROR("software error: relation without existing endpoints.\n");
322                         relation = relation->next;
323                         continue;
324                 }
325                 portlist = epoint->ep_portlist;
326                 if (!portlist)
327                 {
328                         PDEBUG((DEBUG_CALL|DEBUG_PORT), "ignoring relation without interfaces.\n");
329 //#warning testing: keep on hold until single audio stream available
330                         relation->channel_state = CHANNEL_STATE_HOLD;
331                         relation = relation->next;
332                         continue;
333                 }
334                 if (portlist->next)
335                 {
336                         PDEBUG((DEBUG_CALL|DEBUG_PORT), "ignoring relation with ep%d due to port_list.\n", epoint->ep_serial);
337 //#warning testing: keep on hold until single audio stream available
338                         relation->channel_state = CHANNEL_STATE_HOLD;
339                         relation = relation->next;
340                         continue;
341                 }
342                 port = find_port_id(portlist->port_id);
343                 if (!port)
344                 {
345                         PDEBUG((DEBUG_CALL|DEBUG_PORT), "software error: relation without existing port.\n");
346                         relation = relation->next;
347                         continue;
348                 }
349                 if (port->p_record)
350                 {
351                         PDEBUG(DEBUG_CALL|DEBUG_PORT, "mixer(): relation ep%d does recording, so we must get data from all members.\n", epoint->ep_serial);
352                         if (nodata)
353                         {
354                                 PDEBUG(DEBUG_CALL|DEBUG_PORT, "mixer(): at least one endpoint wants data.\n");
355                                 nodata = 0;
356                         }
357                 }
358                 if ((port->p_type&PORT_CLASS_MASK)!=PORT_CLASS_mISDN)
359                 {
360                         PDEBUG((DEBUG_CALL|DEBUG_PORT), "ignoring relation ep%d because it is not mISDN.\n", epoint->ep_serial);
361                         if (nodata)
362                         {
363                                 PDEBUG((DEBUG_CALL|DEBUG_PORT), "not all endpoints are mISDN.\n");
364                                 nodata = 0;
365                         }
366                         relation = relation->next;
367                         continue;
368                 }
369 // remove unconnected parties from conference, also remove remotely disconnected parties so conference will not be disturbed.
370                 if (relation->channel_state == CHANNEL_STATE_CONNECT
371                  && relation->rx_state != NOTIFY_STATE_HOLD
372                  && relation->rx_state != NOTIFY_STATE_SUSPEND)
373                 {
374                         message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, MESSAGE_mISDNSIGNAL);
375                         message->param.mISDNsignal.message = mISDNSIGNAL_CONF;
376                         message->param.mISDNsignal.conf = (c_serial<<1) + 1;
377                         PDEBUG(DEBUG_CALL, "%s +on+ id: 0x%08x\n", port->p_name, message->param.mISDNsignal.conf);
378                         message_put(message);
379                 } else
380                 {
381                         message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, MESSAGE_mISDNSIGNAL);
382                         message->param.mISDNsignal.message = mISDNSIGNAL_CONF;
383                         message->param.mISDNsignal.conf = 0;
384                         PDEBUG(DEBUG_CALL, "%s +off+ id: 0x%08x\n", port->p_name, message->param.mISDNsignal.conf);
385                         message_put(message);
386                 }
387                 relation = relation->next;
388         }
389         /* we notify all relations about rxdata. */
390         relation = c_relation;
391         while(relation)
392         {
393                 message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, MESSAGE_mISDNSIGNAL);
394                 message->param.mISDNsignal.message = mISDNSIGNAL_NODATA;
395                 message->param.mISDNsignal.nodata = nodata;
396                 PDEBUG(DEBUG_CALL, "call %d sets alldata on port %s to %d\n", c_serial, port->p_name, nodata);
397                 message_put(message);
398                 relation = relation->next;
399         }
400
401         /* count relations and states */
402         relation = c_relation;
403         numconnect = 0;
404         relations = 0;
405         while(relation) /* count audio-connected and active relations */
406         {
407                 relations ++;
408                 if ((relation->channel_state == CHANNEL_STATE_CONNECT)
409                  && (relation->rx_state != NOTIFY_STATE_SUSPEND)
410                  && (relation->rx_state != NOTIFY_STATE_HOLD))
411                         numconnect ++;
412                 relation = relation->next;
413         }
414
415         if (relations==2 && !c_partyline) /* two people just exchange their states */
416         {
417                 relation = c_relation;
418                 relation->tx_state = notify_state_change(c_serial, relation->epoint_id, relation->tx_state, relation->next->rx_state);
419                 relation->next->tx_state = notify_state_change(c_serial, relation->next->epoint_id, relation->next->tx_state, relation->rx_state);
420         } else
421         if ((relations==1 || numconnect==1) /*&& !c_partyline*/) /* one member in a call, so we put her on hold */
422         {
423                 relation = c_relation;
424                 while(relation)
425                 {
426                         if ((relation->channel_state == CHANNEL_STATE_CONNECT)
427                          && (relation->rx_state != NOTIFY_STATE_SUSPEND)
428                          && (relation->rx_state != NOTIFY_STATE_HOLD))
429                                 relation->tx_state = notify_state_change(c_serial, relation->epoint_id, relation->tx_state, NOTIFY_STATE_HOLD);
430                         relation = relation->next;
431                 }
432         } else
433         /* if conference/partyline or (more than two members and more than one is connected), so we set conference state */ 
434         {
435                 relation = c_relation;
436                 while(relation)
437                 {
438                         if ((relation->channel_state == CHANNEL_STATE_CONNECT)
439                          && (relation->rx_state != NOTIFY_STATE_SUSPEND)
440                          && (relation->rx_state != NOTIFY_STATE_HOLD))
441                                 relation->tx_state = notify_state_change(c_serial, relation->epoint_id, relation->tx_state, NOTIFY_STATE_CONFERENCE);
442                         relation = relation->next;
443                 }
444         }
445 }
446
447
448 /* send audio data to endpoints which do not come from an endpoint connected
449  * to an isdn port and do not go to an endpoint which is connected to an
450  * isdn port. in this case the mixing cannot be done with kernel space
451  */
452 void CallPBX::call_mixer(unsigned long epoint_from, struct call_relation *relation_from, union parameter *param)
453 {
454         struct call_relation *relation_to;
455         struct message *message;
456
457         /* skip if source endpoint has NOT audio mode CONNECT */
458         if (relation_from->channel_state != CHANNEL_STATE_CONNECT)
459         {
460                 return;
461         }
462
463         /* loop all endpoints and skip the endpoint where the audio is from
464          * so we do not get a loop (echo)
465          */
466         relation_to = c_relation;
467         while(relation_to)
468         {
469                 /* skip source endpoint */
470                 if (relation_to->epoint_id == epoint_from)
471                 {
472                         relation_to = relation_to->next;
473                         continue;
474                 }
475
476                 /* skip if destination endpoint has audio mode HOLD */
477                 if (relation_to->channel_state != CHANNEL_STATE_CONNECT)
478                 {
479                         relation_to = relation_to->next;
480                         continue;
481                 }
482
483                 /* now we may send our data to the endpoint where it
484                  * will be delivered to the port
485                  */
486 //PDEBUG(DEBUG_CALL, "mixing from %d to %d\n", epoint_from, relation_to->epoint_id);
487                 message = message_create(c_serial, relation_to->epoint_id, CALL_TO_EPOINT, MESSAGE_DATA);
488                 memcpy(&message->param, param, sizeof(union parameter));
489                 message_put(message);
490
491                 relation_to = relation_to->next;
492         }
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 mixer */
531         if (relation->channel_state != CHANNEL_STATE_HOLD)
532         {
533                 relation->channel_state = CHANNEL_STATE_HOLD;
534                 c_mixer = 1; /* update mixer 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_PBX)
608                 return(0);
609         callpbx = (class CallPBX *)call;
610
611         i = 0;
612         relation = callpbx->c_relation;
613         while(relation)
614         {
615                 i++;
616                 relation = relation->next;
617         }
618
619         return(i);
620 }
621
622 void CallPBX::remove_relation(struct call_relation *relation)
623 {
624         struct call_relation *temp, **tempp;
625
626         if (!relation)
627                 return;
628
629         temp = c_relation;
630         tempp = &c_relation;
631         while(temp)
632         {
633                 if (temp == relation)
634                         break;
635                 tempp = &temp->next;
636                 temp = temp->next;
637         }
638         if (!temp)
639         {
640                 PERROR("relation not in call.\n");
641                 return;
642         }
643
644         PDEBUG(DEBUG_CALL, "removing relation.\n");
645         *tempp = relation->next;
646         memset(temp, 0, sizeof(struct call_relation));
647         free(temp);
648         cmemuse--;
649 }       
650
651
652 struct call_relation *CallPBX::add_relation(void)
653 {
654         struct call_relation *relation;
655
656         if (!c_relation)
657         {
658                 PERROR("there is no first relation to this call\n");
659                 return(NULL);
660         }
661         relation = c_relation;
662         while(relation->next)
663                 relation = relation->next;
664
665         relation->next = (struct call_relation *)calloc(1, sizeof(struct call_relation));
666         if (!relation->next)
667         {
668                 PERROR("no memory\n");
669                 return(NULL);
670         }
671         cmemuse++;
672         memset(relation->next, 0, sizeof(struct call_relation));
673         /* the record pointer is set at the first time the data is received for the relation */
674
675 //      if (options.deb & DEBUG_CALL)
676 //              callpbx_debug(call, "add_relation");
677         return(relation->next);
678 }
679
680 /* epoint sends a message to a call
681  *
682  */
683 void CallPBX::message_epoint(unsigned long epoint_id, int message_type, union parameter *param)
684 {
685         class Call *cl;
686         struct call_relation *relation, *rel;
687         int num;
688         int new_state;
689         struct message *message;
690 //      int size, writesize, oldpointer;
691         class Endpoint *epoint;
692         char *number;
693
694         if (!epoint_id)
695         {
696                 PERROR("software error, epoint == NULL\n");
697                 return;
698         }
699
700 //      if (options.deb & DEBUG_CALL)
701 //      {
702 //              PDEBUG(DEBUG_CALL, "message %d received from ep%d.\n", message, epoint->ep_serial);
703 //              callpbx_debug(call,"Call::message_epoint");
704 //      }
705         if (options.deb & DEBUG_CALL)
706         {
707                 if (message_type != MESSAGE_DATA)
708                 {
709                         cl = call_first;
710                         while(cl)
711                         {
712                                 if (cl->c_type == CALL_TYPE_PBX)
713                                         callpbx_debug((class CallPBX *)cl, "Call::message_epoint{all calls before processing}");
714                                 cl = cl->next;
715                         }
716                 }
717         }
718
719         /* check relation */
720         relation = c_relation;
721         while(relation)
722         {
723                 if (relation->epoint_id == epoint_id)
724                         break;
725                 relation = relation->next;
726         }
727         if (!relation)
728         {
729 //              PERROR("no relation back to the endpoint found, ignoring (call=%d, endpoint=%d\n", c_serial, epoint_id);
730                 return;
731         }
732
733         switch(message_type)
734         {
735                 /* process channel message */
736                 case MESSAGE_CHANNEL:
737                 PDEBUG(DEBUG_CALL, "call received channel message: %d.\n", param->channel);
738                 if (relation->channel_state != param->channel)
739                 {
740                         relation->channel_state = param->channel;
741                         c_mixer = 1; /* update mixer flag */
742                         if (options.deb & DEBUG_CALL)
743                                 callpbx_debug(this, "Call::message_epoint{after setting new channel state}");
744                 }
745                 return;
746
747                 /* track notify */
748                 case MESSAGE_NOTIFY:
749                 switch(param->notifyinfo.notify)
750                 {
751                         case INFO_NOTIFY_USER_SUSPENDED:
752                         case INFO_NOTIFY_USER_RESUMED:
753                         case INFO_NOTIFY_REMOTE_HOLD:
754                         case INFO_NOTIFY_REMOTE_RETRIEVAL:
755                         case INFO_NOTIFY_CONFERENCE_ESTABLISHED:
756                         case INFO_NOTIFY_CONFERENCE_DISCONNECTED:
757                         new_state = track_notify(relation->rx_state, param->notifyinfo.notify);
758                         if (new_state != relation->rx_state)
759                         {
760                                 relation->rx_state = new_state;
761                                 c_mixer = 1;
762                                 if (options.deb & DEBUG_CALL)
763                                         callpbx_debug(this, "Call::message_epoint{after setting new rx state}");
764                         }
765                         break;
766
767                         default:
768                         /* send notification to all other endpoints */
769                         rel = c_relation;
770                         while(rel)
771                         {
772                                 if (rel->epoint_id!=epoint_id && rel->epoint_id)
773                                 {
774                                         message = message_create(c_serial, rel->epoint_id, CALL_TO_EPOINT, MESSAGE_NOTIFY);
775                                         memcpy(&message->param, param, sizeof(union parameter));
776                                         message_put(message);
777                                 }
778                                 rel = rel->next;
779                         }
780                 }
781                 return;
782
783                 /* audio data */
784                 case MESSAGE_DATA:
785                 /* now send audio data to all endpoints connected */
786                 call_mixer(epoint_id, relation, param);
787                 return;
788         }
789
790         /* process party line */
791         if (message_type == MESSAGE_SETUP) if (param->setup.partyline)
792         {
793                 PDEBUG(DEBUG_CALL, "respsone with connect in partyline mode.\n");
794                 c_partyline = param->setup.partyline;
795                 message = message_create(c_serial, epoint_id, CALL_TO_EPOINT, MESSAGE_CONNECT);
796                 message->param.setup.partyline = c_partyline;
797                 message_put(message);
798                 c_mixer = 1; /* update mixer flag */
799         }
800         if (c_partyline)
801         {
802                 if (message_type == MESSAGE_DISCONNECT)
803                 {
804                         PDEBUG(DEBUG_CALL, "releasing after receiving disconnect, because call in partyline mode.\n");
805 //                      remove_relation(relation);
806                         message = message_create(c_serial, epoint_id, CALL_TO_EPOINT, MESSAGE_RELEASE);
807                         message->param.disconnectinfo.cause = CAUSE_NORMAL;
808                         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
809                         message_put(message);
810 //                      c_mixer = 1; /* update mixer flag */
811                         return;
812                 }
813         }
814         if (c_partyline)
815         {
816                 PDEBUG(DEBUG_CALL, "ignoring message, because call in partyline mode.\n");
817                 return;
818         }
819
820         /* count relations */
821         num=callpbx_countrelations(c_serial);
822
823         /* check number of relations */
824         if (num > 2)
825         {
826                 PDEBUG(DEBUG_CALL, "call has more than two relations so there is no need to send a message.\n");
827                 return;
828         }
829
830         /* find interfaces not related to calling epoint */
831         relation = c_relation;
832         while(relation)
833         {
834                 if (relation->epoint_id != epoint_id)
835                         break;
836                 relation = relation->next;
837         }
838         if (!relation)
839         {
840                 switch(message_type)
841                 {
842                         case MESSAGE_SETUP:
843                         if (param->dialinginfo.itype == INFO_ITYPE_ISDN_EXTENSION)
844                         {
845                                 while(number = strsep(&param->dialinginfo.number, ','))
846                                 {
847                                         if (out_setup(epoint_id, message_type, param, number))
848                                                 return; // call destroyed
849                                 }
850                                 break;
851                         }
852                         if (out_setup(epoint_id, message_type, param, NULL))
853                                 return; // call destroyed
854                         break;
855
856                         default:
857                         PDEBUG(DEBUG_CALL, "no need to send a message because there is no other endpoint than the calling one.\n");
858                 }
859         } else
860         {
861                 PDEBUG(DEBUG_CALL, "sending message ep%ld -> ep%ld.\n", epoint_id, relation->epoint_id);
862                 message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, message_type);
863                 memcpy(&message->param, param, sizeof(union parameter));
864                 message_put(message);
865                 PDEBUG(DEBUG_CALL, "message sent.\n");
866         }
867 }
868
869
870 /* call process is called from the main loop
871  * it processes the current calling state.
872  * returns 0 if call nothing was done
873  */
874 int CallPBX::handler(void)
875 {
876 //      struct call_relation *relation;
877 //      char dialing[32][32];
878 //      int port[32];
879 //      int found;
880 //      int i, j;
881 //      char *p;
882
883         /* the mixer must be updated */
884         if (c_mixer)
885         {
886                 mixer();
887                 c_mixer = 0;
888                 return(1);
889         }
890
891         return(0);
892 }
893
894
895 int track_notify(int oldstate, int notify)
896 {
897         int newstate = oldstate;
898
899         switch(notify)
900         {
901                 case INFO_NOTIFY_USER_RESUMED:
902                 case INFO_NOTIFY_REMOTE_RETRIEVAL:
903                 case INFO_NOTIFY_CONFERENCE_DISCONNECTED:
904                 case INFO_NOTIFY_RESERVED_CT_1:
905                 case INFO_NOTIFY_RESERVED_CT_2:
906                 case INFO_NOTIFY_CALL_IS_DIVERTING:
907                 newstate = NOTIFY_STATE_ACTIVE;
908                 break;
909
910                 case INFO_NOTIFY_USER_SUSPENDED:
911                 newstate = NOTIFY_STATE_SUSPEND;
912                 break;
913
914                 case INFO_NOTIFY_REMOTE_HOLD:
915                 newstate = NOTIFY_STATE_HOLD;
916                 break;
917
918                 case INFO_NOTIFY_CONFERENCE_ESTABLISHED:
919                 newstate = NOTIFY_STATE_CONFERENCE;
920                 break;
921         }
922
923         return(newstate);
924 }
925
926
927 /*
928  * setup to exactly one endpoint
929  * if it fails, the calling endpoint is released.
930  * if other outgoing endpoints already exists, they are release as well.
931  * note: if this functions fails, it will destroy its own call object!
932  */
933 int CallPBX::out_setup(unsigned long epoint_id, int message_type, union parameter *param, char *newnumber)
934 {
935         struct call_relation *relation;
936         struct message *message;
937         class Endpoint *epoint;
938
939         PDEBUG(DEBUG_CALL, "no endpoint found, so we will create an endpoint and send the setup message we have.\n");
940         /* create a new relation */
941         if (!(relation=add_relation()))
942         {
943                 /* release due to error */
944                 ressource_error:
945                 relation = c_relation;
946                 while(relation)
947                 {
948                         message = message_create(c_serial, releation->epoint_id, CALL_TO_EPOINT, MESSAGE_RELEASE);
949                         message->param.disconnectinfo.cause = (relation->epoint_id==epoint_id)CAUSE_RESSOURCEUNAVAIL?:CAUSE_NORMAL; 
950                         message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
951                         message_put(message);
952                         relation = relation->next;
953                 }
954                 delete this;
955                 return(-ENOMEM);
956         }
957         relation->type = RELATION_TYPE_SETUP;
958         relation->channel_state = CHANNEL_STATE_HOLD; /* audio is assumed on a new call */
959         relation->tx_state = NOTIFY_STATE_ACTIVE; /* new calls always assumed to be active */
960         relation->rx_state = NOTIFY_STATE_ACTIVE; /* new calls always assumed to be active */
961         /* create a new endpoint */
962         epoint = new Endpoint(0, c_serial);
963         if (!epoint)
964         {
965                 remove_relation(relation);
966                 goto ressource_error;
967         }
968         if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint)))
969         {
970                 PERROR("ERROR:No endpoint's app.\n");
971                 delete epoint;
972                 remove_relation(relation);
973                 goto ressource_error;
974         }
975         relation->epoint_id = epoint->ep_serial;
976         /* send setup message to new endpoint */
977 //printf("JOLLY DEBUG: %d\n",call_countrelations(c_serial));
978 //i                     if (options.deb & DEBUG_CALL)
979 //                              callpbx_debug(call, "Call::message_epoint");
980         message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, message_type);
981         memcpy(&message->param, param, sizeof(union parameter));
982         if (newnumber)
983                 SCPY(message->param.setup.dialinginfo.number, newnumber);
984         PDEBUG(DEBUG_CALL, "setup message sent to ep %d with number='%s'.\n", relation->epoint_id, message->param.setup.dialinginfo.number);
985         message_put(message);
986         return(0);
987 }
988
989 todo: beim release von einem relation_type_setup muss der cause gesammelt werden, bis keine weitere setup-relation mehr existiert
990 beim letzten den collected cause senden
991 mixer kann ruhig loslegen, das aber dokumentieren
992 mixer überdenken: wer sendet, welche töne verfügbar sind, u.s.w
993