diff options
Diffstat (limited to '1.2-netsec/pbx')
-rw-r--r-- | 1.2-netsec/pbx/Makefile | 80 | ||||
-rw-r--r-- | 1.2-netsec/pbx/dundi-parser.c | 832 | ||||
-rw-r--r-- | 1.2-netsec/pbx/dundi-parser.h | 88 | ||||
-rw-r--r-- | 1.2-netsec/pbx/pbx_ael.c | 1284 | ||||
-rw-r--r-- | 1.2-netsec/pbx/pbx_config.c | 1831 | ||||
-rw-r--r-- | 1.2-netsec/pbx/pbx_dundi.c | 4831 | ||||
-rw-r--r-- | 1.2-netsec/pbx/pbx_gtkconsole.c | 518 | ||||
-rw-r--r-- | 1.2-netsec/pbx/pbx_kdeconsole.cc | 61 | ||||
-rw-r--r-- | 1.2-netsec/pbx/pbx_kdeconsole.h | 37 | ||||
-rw-r--r-- | 1.2-netsec/pbx/pbx_kdeconsole_main.cc | 81 | ||||
-rw-r--r-- | 1.2-netsec/pbx/pbx_loopback.c | 207 | ||||
-rw-r--r-- | 1.2-netsec/pbx/pbx_realtime.c | 274 | ||||
-rw-r--r-- | 1.2-netsec/pbx/pbx_spool.c | 445 |
13 files changed, 0 insertions, 10569 deletions
diff --git a/1.2-netsec/pbx/Makefile b/1.2-netsec/pbx/Makefile deleted file mode 100644 index f86ae4859..000000000 --- a/1.2-netsec/pbx/Makefile +++ /dev/null @@ -1,80 +0,0 @@ -# -# Asterisk -- A telephony toolkit for Linux. -# -# Makefile for PBX modules -# -# Copyright (C) 1999-2005, Mark Spencer -# -# Mark Spencer <markster@digium.com> -# -# This program is free software, distributed under the terms of -# the GNU General Public License -# - -PBX_LIBS=pbx_config.so pbx_spool.so pbx_dundi.so pbx_loopback.so pbx_realtime.so \ - pbx_ael.so - -ifeq ($(findstring BSD,${OSARCH}),BSD) - CFLAGS+=-I$(CROSS_COMPILE_TARGET)/usr/local/include -L$(CROSS_COMPILE_TARGET)/usr/local/lib -endif - -# Add GTK console if appropriate -#PBX_LIBS+=$(shell $(CROSS_COMPILE_BIN)gtk-config --cflags >/dev/null 2>/dev/null && echo "pbx_gtkconsole.so") -# Add KDE Console if appropriate -#PBX_LIBS+=$(shell [ "$$QTDIR" != "" ] && echo "pbx_kdeconsole.so") - -GTK_FLAGS=`${CROSS_COMPILE_BIN}gtk-config --cflags gthread` -GTK_LIBS=`${CROSS_COMPILE_BIN}gtk-config --libs gthread` -MOC=$(QTDIR)/bin/moc -KDE_FLAGS=-I$(KDEDIR)/include -I$(KDEDIR)/include/kde -I$(QTDIR)/include -KDE_LIBS=-L$(KDEDIR)/lib -L$(QTDIR)/lib -lqt -lkdecore -lkdeui - -ifeq (${OSARCH},CYGWIN) -CYGSOLINK=-Wl,--out-implib=lib$@.a -Wl,--export-all-symbols -CYGSOLIB=-L.. -L. -L../res -lasterisk.dll -else -CFLAGS+=-fPIC -endif - -KDE_CONSOLE_OBJS=pbx_kdeconsole_main.o pbx_kdeconsole.o - -all: depend $(PBX_LIBS) - -clean: - rm -f *.so *.o .depend - -pbx_gtkconsole.o: pbx_gtkconsole.c - $(CC) $(CFLAGS) $(GTK_FLAGS) -c -o $@ $< - -pbx_gtkconsole.so: pbx_gtkconsole.o - $(CC) $(SOLINK) -o $@ $< $(GTK_LIBS) - -pbx_kdeconsole.o: pbx_kdeconsole.cc pbx_kdeconsole.moc - $(CXX) $(CFLAGS) $(KDE_FLAGS) -c -o $@ $< - -pbx_kdeconsole_main.o: pbx_kdeconsole_main.cc pbx_kdeconsole.h - $(CXX) $(CFLAGS) $(KDE_FLAGS) -c -o $@ $< - -pbx_kdeconsole.so: $(KDE_CONSOLE_OBJS) - $(CC) $(SOLINK) -o $@ $(KDE_CONSOLE_OBJS) $(KDE_LIBS) - -pbx_dundi.so: dundi-parser.o pbx_dundi.o - $(CC) $(SOLINK) -o $@ ${CYGSOLINK} pbx_dundi.o dundi-parser.o -lz ${CYGSOLIB} - -%.moc : %.h - $(MOC) $< -o $@ - -%.so : %.o - $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} - -ifneq ($(wildcard .depend),) - include .depend -endif - -install: all - for x in $(PBX_LIBS); do $(INSTALL) -m 755 $$x $(DESTDIR)$(MODULES_DIR) ; done - -depend: .depend - -.depend: - ../build_tools/mkdep $(CFLAGS) `ls *.c` diff --git a/1.2-netsec/pbx/dundi-parser.c b/1.2-netsec/pbx/dundi-parser.c deleted file mode 100644 index 9b9d9d205..000000000 --- a/1.2-netsec/pbx/dundi-parser.c +++ /dev/null @@ -1,832 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief Distributed Universal Number Discovery (DUNDi) - * - */ - -#include <sys/types.h> -#include <sys/socket.h> -#include <string.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/frame.h" -#include "asterisk/utils.h" -#include "asterisk/dundi.h" -#include "dundi-parser.h" -#include "asterisk/dundi.h" - -static void internaloutput(const char *str) -{ - fputs(str, stdout); -} - -static void internalerror(const char *str) -{ - fprintf(stderr, "WARNING: %s", str); -} - -static void (*outputf)(const char *str) = internaloutput; -static void (*errorf)(const char *str) = internalerror; - -char *dundi_eid_to_str(char *s, int maxlen, dundi_eid *eid) -{ - int x; - char *os = s; - if (maxlen < 18) { - if (s && (maxlen > 0)) - *s = '\0'; - } else { - for (x=0;x<5;x++) { - sprintf(s, "%02x:", eid->eid[x]); - s += 3; - } - sprintf(s, "%02x", eid->eid[5]); - } - return os; -} - -char *dundi_eid_to_str_short(char *s, int maxlen, dundi_eid *eid) -{ - int x; - char *os = s; - if (maxlen < 13) { - if (s && (maxlen > 0)) - *s = '\0'; - } else { - for (x=0;x<6;x++) { - sprintf(s, "%02X", eid->eid[x]); - s += 2; - } - } - return os; -} - -int dundi_str_to_eid(dundi_eid *eid, char *s) -{ - unsigned int eid_int[6]; - int x; - if (sscanf(s, "%x:%x:%x:%x:%x:%x", &eid_int[0], &eid_int[1], &eid_int[2], - &eid_int[3], &eid_int[4], &eid_int[5]) != 6) - return -1; - for (x=0;x<6;x++) - eid->eid[x] = eid_int[x]; - return 0; -} - -int dundi_str_short_to_eid(dundi_eid *eid, char *s) -{ - unsigned int eid_int[6]; - int x; - if (sscanf(s, "%2x%2x%2x%2x%2x%2x", &eid_int[0], &eid_int[1], &eid_int[2], - &eid_int[3], &eid_int[4], &eid_int[5]) != 6) - return -1; - for (x=0;x<6;x++) - eid->eid[x] = eid_int[x]; - return 0; -} - -int dundi_eid_zero(dundi_eid *eid) -{ - int x; - for (x=0;x<sizeof(eid->eid) / sizeof(eid->eid[0]);x++) - if (eid->eid[x]) return 0; - return 1; -} - -int dundi_eid_cmp(dundi_eid *eid1, dundi_eid *eid2) -{ - return memcmp(eid1, eid2, sizeof(dundi_eid)); -} - -static void dump_string(char *output, int maxlen, void *value, int len) -{ - maxlen--; - if (maxlen > len) - maxlen = len; - strncpy(output,value, maxlen); - output[maxlen] = '\0'; -} - -static void dump_cbypass(char *output, int maxlen, void *value, int len) -{ - maxlen--; - strncpy(output, "Bypass Caches", maxlen); - output[maxlen] = '\0'; -} - -static void dump_eid(char *output, int maxlen, void *value, int len) -{ - if (len == 6) - dundi_eid_to_str(output, maxlen, (dundi_eid *)value); - else - snprintf(output, maxlen, "Invalid EID len %d", len); -} - -char *dundi_hint2str(char *buf, int bufsiz, int flags) -{ - strcpy(buf, ""); - buf[bufsiz-1] = '\0'; - if (flags & DUNDI_HINT_TTL_EXPIRED) { - strncat(buf, "TTLEXPIRED|", bufsiz - strlen(buf) - 1); - } - if (flags & DUNDI_HINT_DONT_ASK) { - strncat(buf, "DONTASK|", bufsiz - strlen(buf) - 1); - } - if (flags & DUNDI_HINT_UNAFFECTED) { - strncat(buf, "UNAFFECTED|", bufsiz - strlen(buf) - 1); - } - /* Get rid of trailing | */ - if (ast_strlen_zero(buf)) - strcpy(buf, "NONE|"); - buf[strlen(buf)-1] = '\0'; - return buf; -} - -static void dump_hint(char *output, int maxlen, void *value, int len) -{ - unsigned short flags; - char tmp[512]; - char tmp2[256]; - if (len < 2) { - strncpy(output, "<invalid contents>", maxlen); - return; - } - memcpy(&flags, value, sizeof(flags)); - flags = ntohs(flags); - memset(tmp, 0, sizeof(tmp)); - dundi_hint2str(tmp2, sizeof(tmp2), flags); - snprintf(tmp, sizeof(tmp), "[%s] ", tmp2); - memcpy(tmp + strlen(tmp), value + 2, len - 2); - strncpy(output, tmp, maxlen - 1); -} - -static void dump_cause(char *output, int maxlen, void *value, int len) -{ - static char *causes[] = { - "SUCCESS", - "GENERAL", - "DYNAMIC", - "NOAUTH" , - }; - char tmp[256]; - char tmp2[256]; - int mlen; - unsigned char cause; - if (len < 1) { - strncpy(output, "<invalid contents>", maxlen); - return; - } - cause = *((unsigned char *)value); - memset(tmp2, 0, sizeof(tmp2)); - mlen = len - 1; - if (mlen > 255) - mlen = 255; - memcpy(tmp2, value + 1, mlen); - if (cause < sizeof(causes) / sizeof(causes[0])) { - if (len > 1) - snprintf(tmp, sizeof(tmp), "%s: %s", causes[cause], tmp2); - else - snprintf(tmp, sizeof(tmp), "%s", causes[cause]); - } else { - if (len > 1) - snprintf(tmp, sizeof(tmp), "%d: %s", cause, tmp2); - else - snprintf(tmp, sizeof(tmp), "%d", cause); - } - - strncpy(output,tmp, maxlen); - output[maxlen] = '\0'; -} - -static void dump_int(char *output, int maxlen, void *value, int len) -{ - if (len == (int)sizeof(unsigned int)) - snprintf(output, maxlen, "%lu", (unsigned long)ntohl(*((unsigned int *)value))); - else - snprintf(output, maxlen, "Invalid INT"); -} - -static void dump_short(char *output, int maxlen, void *value, int len) -{ - if (len == (int)sizeof(unsigned short)) - snprintf(output, maxlen, "%d", ntohs(*((unsigned short *)value))); - else - snprintf(output, maxlen, "Invalid SHORT"); -} - -static void dump_byte(char *output, int maxlen, void *value, int len) -{ - if (len == (int)sizeof(unsigned char)) - snprintf(output, maxlen, "%d", *((unsigned char *)value)); - else - snprintf(output, maxlen, "Invalid BYTE"); -} - -static char *proto2str(int proto, char *buf, int bufsiz) -{ - switch(proto) { - case DUNDI_PROTO_NONE: - strncpy(buf, "None", bufsiz - 1); - break; - case DUNDI_PROTO_IAX: - strncpy(buf, "IAX", bufsiz - 1); - break; - case DUNDI_PROTO_SIP: - strncpy(buf, "SIP", bufsiz - 1); - break; - case DUNDI_PROTO_H323: - strncpy(buf, "H.323", bufsiz - 1); - break; - default: - snprintf(buf, bufsiz, "Unknown Proto(%d)", proto); - } - buf[bufsiz-1] = '\0'; - return buf; -} - -char *dundi_flags2str(char *buf, int bufsiz, int flags) -{ - strcpy(buf, ""); - buf[bufsiz-1] = '\0'; - if (flags & DUNDI_FLAG_EXISTS) { - strncat(buf, "EXISTS|", bufsiz - strlen(buf) - 1); - } - if (flags & DUNDI_FLAG_MATCHMORE) { - strncat(buf, "MATCHMORE|", bufsiz - strlen(buf) - 1); - } - if (flags & DUNDI_FLAG_CANMATCH) { - strncat(buf, "CANMATCH|", bufsiz - strlen(buf) - 1); - } - if (flags & DUNDI_FLAG_IGNOREPAT) { - strncat(buf, "IGNOREPAT|", bufsiz - strlen(buf) - 1); - } - if (flags & DUNDI_FLAG_RESIDENTIAL) { - strncat(buf, "RESIDENCE|", bufsiz - strlen(buf) - 1); - } - if (flags & DUNDI_FLAG_COMMERCIAL) { - strncat(buf, "COMMERCIAL|", bufsiz - strlen(buf) - 1); - } - if (flags & DUNDI_FLAG_MOBILE) { - strncat(buf, "MOBILE", bufsiz - strlen(buf) - 1); - } - if (flags & DUNDI_FLAG_NOUNSOLICITED) { - strncat(buf, "NOUNSLCTD|", bufsiz - strlen(buf) - 1); - } - if (flags & DUNDI_FLAG_NOCOMUNSOLICIT) { - strncat(buf, "NOCOMUNSLTD|", bufsiz - strlen(buf) - 1); - } - /* Get rid of trailing | */ - if (ast_strlen_zero(buf)) - strcpy(buf, "NONE|"); - buf[strlen(buf)-1] = '\0'; - return buf; -} - -static void dump_answer(char *output, int maxlen, void *value, int len) -{ - struct dundi_answer *answer; - char proto[40]; - char flags[40]; - char eid_str[40]; - char tmp[512]=""; - if (len >= 10) { - answer = (struct dundi_answer *)(value); - memcpy(tmp, answer->data, (len >= 500) ? 500 : len - 10); - dundi_eid_to_str(eid_str, sizeof(eid_str), &answer->eid); - snprintf(output, maxlen, "[%s] %d <%s/%s> from [%s]", - dundi_flags2str(flags, sizeof(flags), ntohs(answer->flags)), - ntohs(answer->weight), - proto2str(answer->protocol, proto, sizeof(proto)), - tmp, eid_str); - } else - strncpy(output, "Invalid Answer", maxlen - 1); -} - -static void dump_encrypted(char *output, int maxlen, void *value, int len) -{ - char iv[33]; - int x; - if ((len > 16) && !(len % 16)) { - /* Build up IV */ - for (x=0;x<16;x++) { - snprintf(iv + (x << 1), 3, "%02x", ((unsigned char *)value)[x]); - } - snprintf(output, maxlen, "[IV %s] %d encrypted blocks\n", iv, len / 16); - } else - snprintf(output, maxlen, "Invalid Encrypted Datalen %d", len); -} - -static void dump_raw(char *output, int maxlen, void *value, int len) -{ - int x; - unsigned char *u = value; - output[maxlen - 1] = '\0'; - strcpy(output, "[ "); - for (x=0;x<len;x++) { - snprintf(output + strlen(output), maxlen - strlen(output) - 1, "%02x ", u[x]); - } - strncat(output + strlen(output), "]", maxlen - strlen(output) - 1); -} - -static struct dundi_ie { - int ie; - char *name; - void (*dump)(char *output, int maxlen, void *value, int len); -} ies[] = { - { DUNDI_IE_EID, "ENTITY IDENT", dump_eid }, - { DUNDI_IE_CALLED_CONTEXT, "CALLED CONTEXT", dump_string }, - { DUNDI_IE_CALLED_NUMBER, "CALLED NUMBER", dump_string }, - { DUNDI_IE_EID_DIRECT, "DIRECT EID", dump_eid }, - { DUNDI_IE_ANSWER, "ANSWER", dump_answer }, - { DUNDI_IE_TTL, "TTL", dump_short }, - { DUNDI_IE_VERSION, "VERSION", dump_short }, - { DUNDI_IE_EXPIRATION, "EXPIRATION", dump_short }, - { DUNDI_IE_UNKNOWN, "UKWN DUNDI CMD", dump_byte }, - { DUNDI_IE_CAUSE, "CAUSE", dump_cause }, - { DUNDI_IE_REQEID, "REQUEST EID", dump_eid }, - { DUNDI_IE_ENCDATA, "ENCDATA", dump_encrypted }, - { DUNDI_IE_SHAREDKEY, "SHAREDKEY", dump_raw }, - { DUNDI_IE_SIGNATURE, "SIGNATURE", dump_raw }, - { DUNDI_IE_KEYCRC32, "KEYCRC32", dump_int }, - { DUNDI_IE_HINT, "HINT", dump_hint }, - { DUNDI_IE_DEPARTMENT, "DEPARTMENT", dump_string }, - { DUNDI_IE_ORGANIZATION, "ORGANIZTN", dump_string }, - { DUNDI_IE_LOCALITY, "LOCALITY", dump_string }, - { DUNDI_IE_STATE_PROV, "STATEPROV", dump_string }, - { DUNDI_IE_COUNTRY, "COUNTRY", dump_string }, - { DUNDI_IE_EMAIL, "EMAIL", dump_string }, - { DUNDI_IE_PHONE, "PHONE", dump_string }, - { DUNDI_IE_IPADDR, "ADDRESS", dump_string }, - { DUNDI_IE_CACHEBYPASS, "CBYPASS", dump_cbypass }, -}; - -const char *dundi_ie2str(int ie) -{ - int x; - for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) { - if (ies[x].ie == ie) - return ies[x].name; - } - return "Unknown IE"; -} - -static void dump_ies(unsigned char *iedata, int spaces, int len) -{ - int ielen; - int ie; - int x; - int found; - char interp[1024]; - char tmp[1024]; - if (len < 2) - return; - while(len >= 2) { - ie = iedata[0]; - ielen = iedata[1]; - /* Encrypted data is the remainder */ - if (ie == DUNDI_IE_ENCDATA) - ielen = len - 2; - if (ielen + 2> len) { - snprintf(tmp, (int)sizeof(tmp), "Total IE length of %d bytes exceeds remaining frame length of %d bytes\n", ielen + 2, len); - outputf(tmp); - return; - } - found = 0; - for (x=0;x<(int)sizeof(ies) / (int)sizeof(ies[0]); x++) { - if (ies[x].ie == ie) { - if (ies[x].dump) { - ies[x].dump(interp, (int)sizeof(interp), iedata + 2, ielen); - snprintf(tmp, (int)sizeof(tmp), " %s%-15.15s : %s\n", (spaces ? " " : "" ), ies[x].name, interp); - outputf(tmp); - } else { - if (ielen) - snprintf(interp, (int)sizeof(interp), "%d bytes", ielen); - else - strcpy(interp, "Present"); - snprintf(tmp, (int)sizeof(tmp), " %s%-15.15s : %s\n", (spaces ? " " : "" ), ies[x].name, interp); - outputf(tmp); - } - found++; - } - } - if (!found) { - snprintf(tmp, (int)sizeof(tmp), " %sUnknown IE %03d : Present\n", (spaces ? " " : "" ), ie); - outputf(tmp); - } - iedata += (2 + ielen); - len -= (2 + ielen); - } - outputf("\n"); -} - -void dundi_showframe(struct dundi_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen) -{ - char *pref[] = { - "Tx", - "Rx", - " ETx", - " Erx" }; - char *commands[] = { - "ACK ", - "DPDISCOVER ", - "DPRESPONSE ", - "EIDQUERY ", - "EIDRESPONSE ", - "PRECACHERQ ", - "PRECACHERP ", - "INVALID ", - "UNKNOWN CMD ", - "NULL ", - "REQREQ ", - "REGRESPONSE ", - "CANCEL ", - "ENCRYPT ", - "ENCREJ " }; - char class2[20]; - char *class; - char subclass2[20]; - char *subclass; - char tmp[256]; - char retries[20]; - char iabuf[INET_ADDRSTRLEN]; - if (ntohs(fhi->dtrans) & DUNDI_FLAG_RETRANS) - strcpy(retries, "Yes"); - else - strcpy(retries, "No"); - if ((ntohs(fhi->strans) & DUNDI_FLAG_RESERVED)) { - /* Ignore frames with high bit set to 1 */ - return; - } - if ((fhi->cmdresp & 0x3f) > (int)sizeof(commands)/(int)sizeof(char *)) { - snprintf(class2, (int)sizeof(class2), "(%d?)", fhi->cmdresp); - class = class2; - } else { - class = commands[(int)(fhi->cmdresp & 0x3f)]; - } - snprintf(subclass2, (int)sizeof(subclass2), "%02x", fhi->cmdflags); - subclass = subclass2; - snprintf(tmp, (int)sizeof(tmp), - "%s-Frame Retry[%s] -- OSeqno: %3.3d ISeqno: %3.3d Type: %s (%s)\n", - pref[rx], - retries, fhi->oseqno, fhi->iseqno, class, fhi->cmdresp & 0x40 ? "Response" : "Command"); - outputf(tmp); - snprintf(tmp, (int)sizeof(tmp), - "%s Flags: %s STrans: %5.5d DTrans: %5.5d [%s:%d]%s\n", (rx > 1) ? " " : "", - subclass, ntohs(fhi->strans) & ~DUNDI_FLAG_RESERVED, ntohs(fhi->dtrans) & ~DUNDI_FLAG_RETRANS, - ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port), - fhi->cmdresp & 0x80 ? " (Final)" : ""); - outputf(tmp); - dump_ies(fhi->ies, rx > 1, datalen); -} - -int dundi_ie_append_raw(struct dundi_ie_data *ied, unsigned char ie, void *data, int datalen) -{ - char tmp[256]; - if (datalen > ((int)sizeof(ied->buf) - ied->pos)) { - snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos); - errorf(tmp); - return -1; - } - ied->buf[ied->pos++] = ie; - ied->buf[ied->pos++] = datalen; - memcpy(ied->buf + ied->pos, data, datalen); - ied->pos += datalen; - return 0; -} - -int dundi_ie_append_cause(struct dundi_ie_data *ied, unsigned char ie, unsigned char cause, char *data) -{ - char tmp[256]; - int datalen = data ? strlen(data) + 1 : 1; - if (datalen > ((int)sizeof(ied->buf) - ied->pos)) { - snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos); - errorf(tmp); - return -1; - } - ied->buf[ied->pos++] = ie; - ied->buf[ied->pos++] = datalen; - ied->buf[ied->pos++] = cause; - memcpy(ied->buf + ied->pos, data, datalen-1); - ied->pos += datalen-1; - return 0; -} - -int dundi_ie_append_hint(struct dundi_ie_data *ied, unsigned char ie, unsigned short flags, char *data) -{ - char tmp[256]; - int datalen = data ? strlen(data) + 2 : 2; - if (datalen > ((int)sizeof(ied->buf) - ied->pos)) { - snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos); - errorf(tmp); - return -1; - } - ied->buf[ied->pos++] = ie; - ied->buf[ied->pos++] = datalen; - flags = htons(flags); - memcpy(ied->buf + ied->pos, &flags, sizeof(flags)); - ied->pos += 2; - memcpy(ied->buf + ied->pos, data, datalen-1); - ied->pos += datalen-2; - return 0; -} - -int dundi_ie_append_encdata(struct dundi_ie_data *ied, unsigned char ie, unsigned char *iv, void *data, int datalen) -{ - char tmp[256]; - datalen += 16; - if (datalen > ((int)sizeof(ied->buf) - ied->pos)) { - snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos); - errorf(tmp); - return -1; - } - ied->buf[ied->pos++] = ie; - ied->buf[ied->pos++] = datalen; - memcpy(ied->buf + ied->pos, iv, 16); - ied->pos += 16; - if (data) { - memcpy(ied->buf + ied->pos, data, datalen-16); - ied->pos += datalen-16; - } - return 0; -} - -int dundi_ie_append_answer(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid, unsigned char protocol, unsigned short flags, unsigned short weight, char *data) -{ - char tmp[256]; - int datalen = data ? strlen(data) + 11 : 11; - int x; - unsigned short myw; - if (datalen > ((int)sizeof(ied->buf) - ied->pos)) { - snprintf(tmp, (int)sizeof(tmp), "Out of space for ie '%s' (%d), need %d have %d\n", dundi_ie2str(ie), ie, datalen, (int)sizeof(ied->buf) - ied->pos); - errorf(tmp); - return -1; - } - ied->buf[ied->pos++] = ie; - ied->buf[ied->pos++] = datalen; - for (x=0;x<6;x++) - ied->buf[ied->pos++] = eid->eid[x]; - ied->buf[ied->pos++] = protocol; - myw = htons(flags); - memcpy(ied->buf + ied->pos, &myw, 2); - ied->pos += 2; - myw = htons(weight); - memcpy(ied->buf + ied->pos, &myw, 2); - ied->pos += 2; - memcpy(ied->buf + ied->pos, data, datalen-11); - ied->pos += datalen-11; - return 0; -} - -int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, struct sockaddr_in *sin) -{ - return dundi_ie_append_raw(ied, ie, sin, (int)sizeof(struct sockaddr_in)); -} - -int dundi_ie_append_int(struct dundi_ie_data *ied, unsigned char ie, unsigned int value) -{ - unsigned int newval; - newval = htonl(value); - return dundi_ie_append_raw(ied, ie, &newval, (int)sizeof(newval)); -} - -int dundi_ie_append_short(struct dundi_ie_data *ied, unsigned char ie, unsigned short value) -{ - unsigned short newval; - newval = htons(value); - return dundi_ie_append_raw(ied, ie, &newval, (int)sizeof(newval)); -} - -int dundi_ie_append_str(struct dundi_ie_data *ied, unsigned char ie, char *str) -{ - return dundi_ie_append_raw(ied, ie, str, strlen(str)); -} - -int dundi_ie_append_eid(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid) -{ - return dundi_ie_append_raw(ied, ie, (unsigned char *)eid, sizeof(dundi_eid)); -} - -int dundi_ie_append_byte(struct dundi_ie_data *ied, unsigned char ie, unsigned char dat) -{ - return dundi_ie_append_raw(ied, ie, &dat, 1); -} - -int dundi_ie_append(struct dundi_ie_data *ied, unsigned char ie) -{ - return dundi_ie_append_raw(ied, ie, NULL, 0); -} - -void dundi_set_output(void (*func)(const char *)) -{ - outputf = func; -} - -void dundi_set_error(void (*func)(const char *)) -{ - errorf = func; -} - -int dundi_parse_ies(struct dundi_ies *ies, unsigned char *data, int datalen) -{ - /* Parse data into information elements */ - int len; - int ie; - char tmp[256]; - memset(ies, 0, (int)sizeof(struct dundi_ies)); - ies->ttl = -1; - ies->expiration = -1; - ies->unknowncmd = -1; - ies->cause = -1; - while(datalen >= 2) { - ie = data[0]; - len = data[1]; - if (len > datalen - 2) { - errorf("Information element length exceeds message size\n"); - return -1; - } - switch(ie) { - case DUNDI_IE_EID: - case DUNDI_IE_EID_DIRECT: - if (len != (int)sizeof(dundi_eid)) { - errorf("Improper entity identifer, expecting 6 bytes!\n"); - } else if (ies->eidcount < DUNDI_MAX_STACK) { - ies->eids[ies->eidcount] = (dundi_eid *)(data + 2); - ies->eid_direct[ies->eidcount] = (ie == DUNDI_IE_EID_DIRECT); - ies->eidcount++; - } else - errorf("Too many entities in stack!\n"); - break; - case DUNDI_IE_REQEID: - if (len != (int)sizeof(dundi_eid)) { - errorf("Improper requested entity identifer, expecting 6 bytes!\n"); - } else - ies->reqeid = (dundi_eid *)(data + 2); - break; - case DUNDI_IE_CALLED_CONTEXT: - ies->called_context = (char *)data + 2; - break; - case DUNDI_IE_CALLED_NUMBER: - ies->called_number = (char *)data + 2; - break; - case DUNDI_IE_ANSWER: - if (len < sizeof(struct dundi_answer)) { - snprintf(tmp, (int)sizeof(tmp), "Answer expected to be >=%d bytes long but was %d\n", (int)sizeof(struct dundi_answer), len); - errorf(tmp); - } else { - if (ies->anscount < DUNDI_MAX_ANSWERS) - ies->answers[ies->anscount++]= (struct dundi_answer *)(data + 2); - else - errorf("Ignoring extra answers!\n"); - } - break; - case DUNDI_IE_TTL: - if (len != (int)sizeof(unsigned short)) { - snprintf(tmp, (int)sizeof(tmp), "Expecting ttl to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len); - errorf(tmp); - } else - ies->ttl = ntohs(*((unsigned short *)(data + 2))); - break; - case DUNDI_IE_VERSION: - if (len != (int)sizeof(unsigned short)) { - snprintf(tmp, (int)sizeof(tmp), "Expecting version to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len); - errorf(tmp); - } else - ies->version = ntohs(*((unsigned short *)(data + 2))); - break; - case DUNDI_IE_EXPIRATION: - if (len != (int)sizeof(unsigned short)) { - snprintf(tmp, (int)sizeof(tmp), "Expecting expiration to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len); - errorf(tmp); - } else - ies->expiration = ntohs(*((unsigned short *)(data + 2))); - break; - case DUNDI_IE_KEYCRC32: - if (len != (int)sizeof(unsigned int)) { - snprintf(tmp, (int)sizeof(tmp), "Expecting expiration to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len); - errorf(tmp); - } else - ies->keycrc32 = ntohl(*((unsigned int *)(data + 2))); - break; - case DUNDI_IE_UNKNOWN: - if (len == 1) - ies->unknowncmd = data[2]; - else { - snprintf(tmp, (int)sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len); - errorf(tmp); - } - break; - case DUNDI_IE_CAUSE: - if (len >= 1) { - ies->cause = data[2]; - ies->causestr = (char *)data + 3; - } else { - snprintf(tmp, (int)sizeof(tmp), "Expected at least one byte cause, but was %d long\n", len); - errorf(tmp); - } - break; - case DUNDI_IE_HINT: - if (len >= 2) { - ies->hint = (struct dundi_hint *)(data + 2); - } else { - snprintf(tmp, (int)sizeof(tmp), "Expected at least two byte hint, but was %d long\n", len); - errorf(tmp); - } - break; - case DUNDI_IE_DEPARTMENT: - ies->q_dept = (char *)data + 2; - break; - case DUNDI_IE_ORGANIZATION: - ies->q_org = (char *)data + 2; - break; - case DUNDI_IE_LOCALITY: - ies->q_locality = (char *)data + 2; - break; - case DUNDI_IE_STATE_PROV: - ies->q_stateprov = (char *)data + 2; - break; - case DUNDI_IE_COUNTRY: - ies->q_country = (char *)data + 2; - break; - case DUNDI_IE_EMAIL: - ies->q_email = (char *)data + 2; - break; - case DUNDI_IE_PHONE: - ies->q_phone = (char *)data + 2; - break; - case DUNDI_IE_IPADDR: - ies->q_ipaddr = (char *)data + 2; - break; - case DUNDI_IE_ENCDATA: - /* Recalculate len as the remainder of the message, regardless of - theoretical length */ - len = datalen - 2; - if ((len > 16) && !(len % 16)) { - ies->encblock = (struct dundi_encblock *)(data + 2); - ies->enclen = len - 16; - } else { - snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted data length %d\n", len); - errorf(tmp); - } - break; - case DUNDI_IE_SHAREDKEY: - if (len == 128) { - ies->encsharedkey = (unsigned char *)(data + 2); - } else { - snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted shared key length %d\n", len); - errorf(tmp); - } - break; - case DUNDI_IE_SIGNATURE: - if (len == 128) { - ies->encsig = (unsigned char *)(data + 2); - } else { - snprintf(tmp, (int)sizeof(tmp), "Invalid encrypted signature length %d\n", len); - errorf(tmp); - } - break; - case DUNDI_IE_CACHEBYPASS: - ies->cbypass = 1; - break; - default: - snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", dundi_ie2str(ie), ie, len); - outputf(tmp); - } - /* Overwrite information element with 0, to null terminate previous portion */ - data[0] = 0; - datalen -= (len + 2); - data += (len + 2); - } - /* Null-terminate last field */ - *data = '\0'; - if (datalen) { - errorf("Invalid information element contents, strange boundary\n"); - return -1; - } - return 0; -} diff --git a/1.2-netsec/pbx/dundi-parser.h b/1.2-netsec/pbx/dundi-parser.h deleted file mode 100644 index 62bbf4384..000000000 --- a/1.2-netsec/pbx/dundi-parser.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Distributed Universal Number Discovery (DUNDi) - * - * Copyright (C) 2004 - 2005, Digium Inc. - * - * Written by Mark Spencer <markster@digium.com> - * - * This program is Free Software distributed under the terms of - * of the GNU General Public License. - */ - -#ifndef _DUNDI_PARSER_H -#define _DUNDI_PARSER_H - -#include "asterisk/dundi.h" -#include "asterisk/aes.h" - -#define DUNDI_MAX_STACK 512 -#define DUNDI_MAX_ANSWERS 100 - -struct dundi_ies { - dundi_eid *eids[DUNDI_MAX_STACK + 1]; - int eid_direct[DUNDI_MAX_STACK + 1]; - dundi_eid *reqeid; - int eidcount; - char *called_context; - char *called_number; - struct dundi_answer *answers[DUNDI_MAX_ANSWERS + 1]; - struct dundi_hint *hint; - int anscount; - int ttl; - int version; - int expiration; - int unknowncmd; - unsigned char *pubkey; - int cause; - char *q_dept; - char *q_org; - char *q_locality; - char *q_stateprov; - char *q_country; - char *q_email; - char *q_phone; - char *q_ipaddr; - char *causestr; - unsigned char *encsharedkey; - unsigned char *encsig; - unsigned long keycrc32; - struct dundi_encblock *encblock; - int enclen; - int cbypass; -}; - -struct dundi_ie_data { - int pos; - unsigned char buf[8192]; -}; - -/* Choose a different function for output */ -extern void dundi_set_output(void (*output)(const char *data)); -/* Choose a different function for errors */ -extern void dundi_set_error(void (*output)(const char *data)); -extern void dundi_showframe(struct dundi_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen); - -extern const char *dundi_ie2str(int ie); - -extern int dundi_ie_append_raw(struct dundi_ie_data *ied, unsigned char ie, void *data, int datalen); -extern int dundi_ie_append_addr(struct dundi_ie_data *ied, unsigned char ie, struct sockaddr_in *sin); -extern int dundi_ie_append_int(struct dundi_ie_data *ied, unsigned char ie, unsigned int value); -extern int dundi_ie_append_short(struct dundi_ie_data *ied, unsigned char ie, unsigned short value); -extern int dundi_ie_append_str(struct dundi_ie_data *ied, unsigned char ie, char *str); -extern int dundi_ie_append_eid(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid); -extern int dundi_ie_append_cause(struct dundi_ie_data *ied, unsigned char ie, unsigned char cause, char *desc); -extern int dundi_ie_append_hint(struct dundi_ie_data *ied, unsigned char ie, unsigned short flags, char *data); -extern int dundi_ie_append_answer(struct dundi_ie_data *ied, unsigned char ie, dundi_eid *eid, unsigned char protocol, unsigned short flags, unsigned short weight, char *desc); -extern int dundi_ie_append_encdata(struct dundi_ie_data *ied, unsigned char ie, unsigned char *iv, void *data, int datalen); -extern int dundi_ie_append_byte(struct dundi_ie_data *ied, unsigned char ie, unsigned char dat); -extern int dundi_ie_append(struct dundi_ie_data *ied, unsigned char ie); -extern int dundi_parse_ies(struct dundi_ies *ies, unsigned char *data, int datalen); -extern char *dundi_eid_to_str(char *s, int maxlen, dundi_eid *eid); -extern char *dundi_eid_to_str_short(char *s, int maxlen, dundi_eid *eid); -extern int dundi_str_to_eid(dundi_eid *eid, char *s); -extern int dundi_str_short_to_eid(dundi_eid *eid, char *s); -extern int dundi_eid_zero(dundi_eid *eid); -extern int dundi_eid_cmp(dundi_eid *eid1, dundi_eid *eid2); -extern char *dundi_flags2str(char *s, int maxlen, int flags); -extern char *dundi_hint2str(char *s, int maxlen, int flags); -#endif diff --git a/1.2-netsec/pbx/pbx_ael.c b/1.2-netsec/pbx/pbx_ael.c deleted file mode 100644 index 4b758a61b..000000000 --- a/1.2-netsec/pbx/pbx_ael.c +++ /dev/null @@ -1,1284 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief Compile symbolic Asterisk Extension Logic into Asterisk extensions - * - */ - -#include <sys/types.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <errno.h> - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/pbx.h" -#include "asterisk/config.h" -#include "asterisk/module.h" -#include "asterisk/logger.h" -#include "asterisk/cli.h" -#include "asterisk/callerid.h" - -struct stringlink { - struct stringlink *next; - char data[0]; -}; - -#define FILLIN_BREAK 1 -#define FILLIN_CONTINUE 2 - -struct fillin { - struct fillin *next; - char exten[AST_MAX_EXTENSION]; - int priority; - int type; -}; - -#ifdef __AST_DEBUG_MALLOC -static void FREE(void *ptr) -{ - free(ptr); -} -#else -#define FREE free -#endif - -#define DEBUG_READ (1 << 0) -#define DEBUG_TOKENS (1 << 1) -#define DEBUG_MACROS (1 << 2) -#define DEBUG_CONTEXTS (1 << 3) - -static int aeldebug = 0; - -static char *dtext = "Asterisk Extension Language Compiler"; -static char *config = "extensions.ael"; -static char *registrar = "pbx_ael"; - -static char *__grab_token(char *src, const char *filename, int lineno, int link) -{ - char *c; - char *b; - char *a; - int level = 0; - char *ret; -#if 0 - if (aeldebug || DEBUG_TOKENS) - ast_verbose("Searching for token in '%s'!\n", src); -#endif - c = src; - while(*c) { - if ((*c == '\\')) { - c++; - if (!*c) - c--; - } else { - if ((*c == '{') || (*c == '(')) { - level++; - } else if ((*c == '}') || (*c == ')')) { - if (level) - level--; - else - ast_log(LOG_WARNING, "Syntax error at line %d of '%s', too many closing braces!\n", lineno, filename); - } else if ((*c == ';') && !level) { - /* Got a token! */ - *c = '\0'; - b = c; - b--; - c++; - while((b > src) && (*b < 33)) { - *b = '\0'; - b--; - } - a = ast_skip_blanks(src); - if (link) { - ret = malloc(strlen(a) + sizeof(struct stringlink) + 1); - if (ret) - strcpy(ret + sizeof(struct stringlink), a); - } else - ret = strdup(a); - /* Save remainder */ - memmove(src, c, strlen(c) + 1); - return ret; - } - } - c++; - } - return NULL; -} - -static char *grab_token(char *src, const char *filename, int lineno) -{ - return __grab_token(src, filename, lineno, 0); -} - -static struct stringlink *arg_parse(char *args, const char *filename, int lineno) -{ - struct stringlink *cur, *prev=NULL, *root=NULL; - if (args) { - if (aeldebug & DEBUG_TOKENS) - ast_verbose("Parsing args '%s'!\n", args); - if (args[0] == '{') { - /* Strip mandatory '}' from end */ - args[strlen(args) - 1] = '\0'; - while ((cur = (struct stringlink *)__grab_token(args + 1, filename, lineno, 1))) { - cur->next = NULL; - if (prev) - prev->next = cur; - else - root = cur; - prev = cur; - } - } else if (*args) { - root = malloc(sizeof(struct stringlink) + strlen(args) + 1); - if (root) { - strcpy(root->data, args); - root->next = NULL; - } - } - } - return root; -} - -static char *grab_else(char *args, const char *filename, int lineno) -{ - char *ret = NULL; - int level=0; - char *c; - if (args) { - if (args[0] == '{') { - c = args; - while(*c) { - if (*c == '{') - level++; - else if (*c == '}') { - level--; - if (!level) { - c++; - while(*c && (*c < 33)) { *c = '\0'; c++; }; - if (!strncasecmp(c, "else", 4) && - ((c[4] == '{') || (c[4] < 33))) { - /* Ladies and gentlemen, we have an else clause */ - *c = '\0'; - c += 4; - c = ast_skip_blanks(c); - ret = c; - if (aeldebug & DEBUG_TOKENS) - ast_verbose("Returning else clause '%s'\n", c); - } - break; - } - } - c++; - } - } - } - return ret; -} - -static struct stringlink *param_parse(char *parms, const char *macro, const char *filename, int lineno) -{ - char *s, *e; - struct stringlink *root = NULL, *prev=NULL, *cur; - if (!parms || !*parms) - return NULL; - if (*parms != '(') { - ast_log(LOG_NOTICE, "Syntax error in parameter list for macro '%s' at about line %d of %s: Expecting '(' but got '%c'\n", macro, lineno, filename, *parms); - return NULL; - } - s = parms + 1; - while(*s) { - s = ast_skip_blanks(s); - e = s; - while(*e && (*e != ')') && (*e != ',')) { - if (*e < 33) - *e = '\0'; - e++; - } - if (*e) { - /* Strip token */ - *e = '\0'; - e++; - /* Skip over whitespace */ - e = ast_skip_blanks(e); - /* Link */ - cur = malloc(strlen(s) + sizeof(struct stringlink) + 1); - if (cur) { - cur->next = NULL; - strcpy(cur->data, s); - if (prev) - prev->next = cur; - else - root = cur; - prev = cur; - } - s = e; - } - } - return root; -} - -static void arg_free(struct stringlink *cur) -{ - struct stringlink *last; - while(cur) { - last = cur; - cur = cur->next; - free(last); - } -} - -static void handle_globals(struct stringlink *vars) -{ - while(vars) { - pbx_builtin_setvar(NULL, vars->data); - vars = vars->next; - } -} - -static struct stringlink *split_token(char *token, const char *filename, int lineno) -{ - char *args, *p; - struct stringlink *argv; - args = token; - while (*args && (*args > 32) && (*args != '{') && (*args != '(')) args++; - if (*args) { - p = args; - args = ast_skip_blanks(args); - if (*args != '(') { - *p = '\0'; - } else { - while (*args && (*args != ')')) args++; - if (*args == ')') { - args++; - args = ast_skip_blanks(args); - } - } - if (!*args) - args = NULL; - } else args = NULL; - argv = arg_parse(args, filename, lineno); - if (args) - *args = '\0'; - return argv; -} - -static int matches_keyword(const char *data, const char *keyword) -{ - char c; - if (!strncasecmp(data, keyword, strlen(keyword))) { - c = data[strlen(keyword)]; - if ((c < 33) || (c == '(') || (c == '{')) - return 1; - } - return 0; -} - -static struct stringlink *split_params(char *token, const char *filename, int lineno) -{ - char *params; - struct stringlink *paramv; - params = token; - while(*params && (*params > 32) && (*params != '(')) params++; - if (*params) { - if (*params != '(') { - *params = '\0'; - params++; - params = ast_skip_blanks(params); - } - if (!*params) - params = NULL; - } else params = NULL; - paramv = param_parse(params, token, filename, lineno); - if (params) - *params = '\0'; - return paramv; -} - -static const char *get_case(char *s, char **restout, int *pattern) -{ - char *newcase=NULL; - char *rest=NULL; - if (!strncasecmp(s, "case", 4) && s[4] && ((s[4] < 33) || (s[4] == ':'))) { - newcase = s + 4; - newcase = ast_skip_blanks(newcase); - rest = newcase; - *pattern = 0; - } else if (!strncasecmp(s, "pattern", 7) && s[7] && ((s[7] < 33) || (s[7] == ':'))) { - newcase = s + 8; - newcase = ast_skip_blanks(newcase); - rest = newcase; - *pattern = 1; - } else if (!strncasecmp(s, "default", 7) && ((s[7] < 33) || (s[7] == ':'))) { - newcase = "."; - rest = s + 7; - rest = ast_skip_blanks(rest); - *pattern = 1; - } - - if (rest) { - while (*rest && (*rest > 32) && (*rest != ':')) rest++; - if (*rest) { - *rest = 0; - rest++; - while (*rest && ((*rest == ':') || (*rest < 33))) rest++; - *restout = rest; - } else { - *restout = ""; - } - } else - *restout = s; - if (aeldebug & DEBUG_TOKENS) - ast_verbose("GETCASE: newcase is '%s', rest = '%s'\n", newcase, *restout); - return newcase; -} - -static void fillin_free(struct fillin *fillin) -{ - struct fillin *cur, *next; - cur = fillin; - while(cur) { - next = cur->next; - free(cur); - cur = next; - } -} - -static void fillin_process(struct ast_context *con, struct fillin *fillin, const char *filename, int lineno, const char *breakexten, int breakprio, const char *contexten, int contprio) -{ - struct fillin *cur; - char *app; - char mdata[AST_MAX_EXTENSION + 20]; - cur = fillin; - while(cur) { - if (cur->type == FILLIN_BREAK) { - if (breakexten && breakprio) { - app = "Goto"; - snprintf(mdata, sizeof(mdata), "%s|%d", breakexten, breakprio); - } else { - app = "NoOp"; - snprintf(mdata, sizeof(mdata), "Invalid break"); - ast_log(LOG_NOTICE, "Ignoring inappropriate break around line %d of %s\n", lineno, filename); - } - if (ast_add_extension2(con, 0, cur->exten, cur->priority, NULL, NULL, app, strdup(mdata), FREE, registrar)) - ast_log(LOG_WARNING, "Unable to add step at priority '%d' of break '%s'\n", cur->priority, cur->exten); - } else if (cur->type == FILLIN_CONTINUE) { - if (contexten && contprio) { - app = "Goto"; - snprintf(mdata, sizeof(mdata), "%s|%d", contexten, contprio); - } else { - app = "NoOp"; - snprintf(mdata, sizeof(mdata), "Invalid continue"); - ast_log(LOG_NOTICE, "Ignoring inappropriate continue around line %d of %s\n", lineno, filename); - } - if (ast_add_extension2(con, 0, cur->exten, cur->priority, NULL, NULL, app, strdup(mdata), FREE, registrar)) - ast_log(LOG_WARNING, "Unable to add step at priority '%d' of continue '%s'\n", cur->priority, cur->exten); - } else { - ast_log(LOG_WARNING, "Whoa, unknown fillin type '%d'\n", cur->type); - } - cur = cur->next; - } -} - -static int match_assignment(char *variable, char **value) -{ - char *c; - char *ws; - int inpar = 0; - c = variable; - - while (*c) { - if(*c == ')' && (inpar > 0)) { - inpar--; - } else if(*c == '(' && (inpar >= 0)) { - inpar++; - } else if(*c == '=' && (inpar == 0)) { - break; - } - c++; - } - ws = c; - c = ast_skip_blanks(c); - if (*c == '=') { - *ws = '\0'; - *c = '\0'; - c++; - c = ast_skip_blanks(c); - *value = c; - return 1; - } - return 0; -} - -static int matches_label(char *data, char **rest) -{ - char last = 0; - char *start = data; - while (*data > 32) { - last = *data; - data++; - } - if (last != ':') { - data = ast_skip_blanks(data); - last = *data; - data++; - } - if (last == ':') { - *rest = data; - /* Go back and trim up the label */ - while(*start && ((*start > 32) && (*start != ':'))) start++; - *start = '\0'; - return 1; - } - return 0; -} - -static char *argument_end(char *str) -{ - int level=0; - while(*++str) { - switch(*str) { - case '(': - level++; - break; - case ')': - if(level) - level--; - else - return str; - break; - default: - break; - } - } - return NULL; -} - -static int build_step(const char *what, const char *name, const char *filename, int lineno, struct ast_context *con, char *exten, int *pos, char *data, struct fillin **fillout, char **label); -static int __build_step(const char *what, const char *name, const char *filename, int lineno, struct ast_context *con, char *exten, int *pos, char *data, struct fillin **fillout, char **label) -{ - char *app; - char *args; - char *c; - char *margs=NULL; - char *oargs; - char *rest; - const char *curcase, *newcase; - struct stringlink *swargs, *cur; - int cpos; - int mlen; - int pattern = 0; - struct fillin *fillin; - - data = ast_skip_blanks(data); - if (matches_label(data, &c)) { - *label = data; - data = c; - data = ast_skip_blanks(data); - } - if (ast_strlen_zero(data)) - return 0; - if (matches_keyword(data, "switch")) { - fillin = NULL; - /* Switch */ - args = data + strlen("switch"); - while ((*args < 33) && (*args != '(')) args++; - if ((*args == '(') && (c = argument_end(args))) { - args++; - *c = '\0'; - c++; - if (aeldebug & DEBUG_TOKENS) - ast_verbose("--SWITCH on : %s\n", args); - mlen = strlen(exten) + 128 + strlen(args) + strlen(name); - margs = alloca(mlen); - app = "Goto"; - sprintf(margs, "sw-%d-%s|1", *pos, args); - ast_process_quotes_and_slashes(margs, ',', '|'); - oargs = args; - args = margs; - if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(args), FREE, registrar)) - ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name); - else { - *label = NULL; - (*pos)++; - } - app = "NoOp"; - sprintf(margs, "Finish switch-%d", *pos - 1); - if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(args), FREE, registrar)) - ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name); - else { - *label = NULL; - (*pos)++; - } - c = ast_skip_blanks(c); - if (aeldebug & DEBUG_TOKENS) - ast_verbose("ARG Parsing '%s'\n", c); - swargs = arg_parse(c, filename, lineno); - cur = swargs; - curcase = NULL; - while(cur) { - if ((newcase = get_case(cur->data, &rest, &pattern))) { - if (aeldebug & DEBUG_TOKENS) - ast_verbose("--NEWCASE: '%s'!\n", newcase); - if (curcase) { - /* Handle fall through */ - char tmp[strlen(newcase) + strlen(name) + 40]; - sprintf(tmp, "sw-%d-%s|%d", *pos - 2, newcase, 1); - ast_add_extension2(con, 0, margs, cpos, NULL, NULL, "Goto", strdup(tmp), FREE, registrar); - } - curcase = newcase; - cpos = 1; - if (pattern) - snprintf(margs, mlen, "_sw-%d-%s", *pos - 2, curcase); - else - snprintf(margs, mlen, "sw-%d-%s", *pos - 2, curcase); - if (!strcasecmp(rest, "break")) { - char tmp[strlen(exten) + 10]; - sprintf(tmp, "%s|%d", exten, *pos - 1); - ast_add_extension2(con, 0, exten, cpos, *label, NULL, "Goto", strdup(tmp), FREE, registrar); - curcase = NULL; - *label = NULL; - } else - build_step("switch", margs, filename, lineno, con, margs, &cpos, rest, &fillin, label); - } else if (curcase) { - if (aeldebug & DEBUG_TOKENS) - ast_verbose("Building statement from '%s'\n", rest); - if (!strcasecmp(rest, "break")) { - char tmp[strlen(exten) + 10]; - sprintf(tmp, "%s|%d", exten, *pos - 1); - ast_add_extension2(con, 0, margs, cpos, *label, NULL, "Goto", strdup(tmp), FREE, registrar); - curcase = NULL; - *label = NULL; - } else - build_step("switch", margs, filename, lineno, con, margs, &cpos, rest, &fillin, label); - } else - ast_log(LOG_WARNING, "Unreachable code in switch at about line %d of %s\n", lineno, filename); - if (aeldebug & DEBUG_TOKENS) - ast_verbose("--SWARG: %s\n", cur->data); - cur = cur->next; - } - /* Can't do anything with these */ - fillin_process(con, fillin, filename, lineno, NULL, 0, NULL, 0); - fillin_free(fillin); - arg_free(swargs); - } else - ast_log(LOG_WARNING, "Syntax error in switch declaration in %s around line %d!\n", filename, lineno); - - } else if (matches_keyword(data, "if")) { - /* If... */ - args = data + strlen("if"); - while ((*args < 33) && (*args != '(')) args++; - if ((*args == '(') && (c = argument_end(args))) { - int ifblock; - int ifstart; - int elsestart; - int ifend; - int ifskip; - char *elses; - char *iflabel; - args++; - *c = '\0'; - c++; - c = ast_skip_blanks(c); - if (aeldebug & DEBUG_TOKENS) - ast_verbose("--IF on : '%s' : '%s'\n", args, c); - mlen = strlen(exten) + 128 + strlen(args) + strlen(name); - margs = alloca(mlen); - /* Remember where the ifblock starts, and skip over */ - ifblock = (*pos)++; - iflabel = *label; - *label = NULL; - /* Remember where the start of the ifblock is */ - ifstart = *pos; - snprintf(margs, mlen, "if-%s-%d", name, ifblock); - /* Now process the block of the if */ - if (aeldebug & DEBUG_TOKENS) - ast_verbose("Searching for elses in '%s'\n", c); - elses = grab_else(c, filename, lineno); - build_step("if", margs, filename, lineno, con, exten, pos, c, fillout, label); - if (elses) { - /* Reserve a goto to exit the if */ - ifskip = *pos; - (*pos)++; - elsestart = *pos; - build_step("else", margs, filename, lineno, con, exten, pos, elses, fillout, label); - } else { - elsestart = *pos; - ifskip = 0; - } - ifend = *pos; - (*pos)++; - app = "NoOp"; - snprintf(margs, mlen, "Finish if-%s-%d", name, ifblock); - if (ast_add_extension2(con, 0, exten, ifend, *label, NULL, app, strdup(margs), FREE, registrar)) - ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name); - *label = NULL; - app = "GotoIf"; - snprintf(margs, mlen, "$[ %s ]?%d:%d", args, ifstart, elsestart); - if (ast_add_extension2(con, 0, exten, ifblock, iflabel, NULL, app, strdup(margs), FREE, registrar)) - ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name); - if (ifskip) { - /* Skip as appropriate around else clause */ - snprintf(margs, mlen, "%d", ifend); - if (ast_add_extension2(con, 0, exten, ifskip, NULL, NULL, "Goto", strdup(margs), FREE, registrar)) - ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name); - } - } else - ast_log(LOG_WARNING, "Syntax error in if declaration in %s around line %d!\n", filename, lineno); - } else if (matches_keyword(data, "while")) { - /* While... */ - fillin = NULL; - args = data + strlen("while"); - while ((*args < 33) && (*args != '(')) args++; - if ((*args == '(') && (c = argument_end(args))) { - int whileblock; - int whilestart; - int whileend; - char *whilelabel; - args++; - *c = '\0'; - c++; - c = ast_skip_blanks(c); - if (aeldebug & DEBUG_TOKENS) - ast_verbose("--WHILE on : '%s' : '%s'\n", args, c); - mlen = strlen(exten) + 128 + strlen(args) + strlen(name); - margs = alloca(mlen); - /* Remember where to put the conditional, and keep its position */ - whilestart = (*pos); - whilelabel = *label; - *label = NULL; - (*pos)++; - /* Remember where the whileblock starts */ - whileblock = (*pos); - snprintf(margs, mlen, "while-%s-%d", name, whilestart); - build_step("while", margs, filename, lineno, con, exten, pos, c, &fillin, label); - /* Close the loop */ - app = "Goto"; - snprintf(margs, mlen, "%d", whilestart); - if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar)) - ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name); - *label = NULL; - whileend = (*pos); - /* Place trailer */ - app = "NoOp"; - snprintf(margs, mlen, "Finish while-%s-%d", name, whilestart); - if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar)) - ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name); - *label = NULL; - app = "GotoIf"; - snprintf(margs, mlen, "$[ %s ]?%d:%d", args, whileblock, whileend); - if (ast_add_extension2(con, 0, exten, whilestart, whilelabel, NULL, app, strdup(margs), FREE, registrar)) - ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name); - fillin_process(con, fillin, filename, lineno, exten, whileend, exten, whilestart); - fillin_free(fillin); - } else - ast_log(LOG_WARNING, "Syntax error in while declaration in %s around line %d!\n", filename, lineno); - } else if (matches_keyword(data, "jump")) { - char *p; - /* Jump... */ - fillin = NULL; - args = data + strlen("jump"); - args = ast_skip_blanks(args); - if (aeldebug & DEBUG_TOKENS) - ast_verbose("--JUMP to : '%s'\n", args); - p = strchr(args, ','); - if (p) { - *p = '\0'; - p++; - } else - p = "1"; - c = strchr(args, '@'); - if (c) { - *c = '\0'; - c++; - } - mlen = strlen(exten) + 128 + strlen(args) + strlen(name) + (c ? strlen(c) : 0); - margs = alloca(mlen); - if (c) - snprintf(margs, mlen, "%s|%s|%s", c,args, p); - else - snprintf(margs, mlen, "%s|%s", args, p); - app = "Goto"; - if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar)) - ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name); - *label = NULL; - } else if (matches_keyword(data, "goto")) { - /* Jump... */ - fillin = NULL; - args = data + strlen("goto"); - args = ast_skip_blanks(args); - if (aeldebug & DEBUG_TOKENS) - ast_verbose("--GOTO to : '%s'\n", args); - app = "Goto"; - if (args[0] == '(' && args[strlen(args) - 1] == ')') { - args[0] = '\0'; - args++; - args[strlen(args) - 1] = '\0'; - } - if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(args), FREE, registrar)) - ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name); - *label = NULL; - } else if (matches_keyword(data, "for")) { - /* While... */ - fillin = NULL; - args = data + strlen("for"); - while ((*args < 33) && (*args != '(')) args++; - if ((*args == '(') && (c = argument_end(args))) { - int forblock; - int forprep; - int forstart; - int forend; - struct stringlink *fields; - char *tmp; - char *forlabel = NULL; - args++; - *c = '\0'; - c++; - c = ast_skip_blanks(c); - /* Parse arguments first */ - tmp = alloca(strlen(args) + 10); - if (tmp) { - snprintf(tmp, strlen(args) + 10, "{%s;}", args); - fields = arg_parse(tmp, filename, lineno); - } else - fields = NULL; - if (fields && fields->next && fields->next->next) { - if (aeldebug & DEBUG_TOKENS) - ast_verbose("--FOR ('%s' ; '%s' ; '%s') : '%s'\n", fields->data, fields->next->data, fields->next->next->data, c); - mlen = strlen(exten) + 128 + strlen(args) + strlen(name); - margs = alloca(mlen); - forprep = *pos; - snprintf(margs, mlen, "for-%s-%d", name, forprep); - fillin = NULL; - build_step("while", margs, filename, lineno, con, exten, pos, fields->data, &fillin, label); - /* Remember where to put the conditional, and keep its position */ - forstart = (*pos); - forlabel = *label; - (*pos)++; - *label = NULL; - /* Remember where the whileblock starts */ - forblock = (*pos); - build_step("for", margs, filename, lineno, con, exten, pos, fields->next->next->data, &fillin, label); - build_step("for", margs, filename, lineno, con, exten, pos, c, &fillin, label); - /* Close the loop */ - app = "Goto"; - snprintf(margs, mlen, "%d", forstart); - if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar)) - ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name); - *label = NULL; - forend = (*pos); - /* Place trailer */ - app = "NoOp"; - snprintf(margs, mlen, "Finish for-%s-%d", name, forprep); - if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar)) - ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name); - *label = NULL; - app = "GotoIf"; - snprintf(margs, mlen, "$[ %s ]?%d:%d", fields->next->data, forblock, forend); - if (ast_add_extension2(con, 0, exten, forstart, forlabel, NULL, app, strdup(margs), FREE, registrar)) - ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", forstart, what, name); - fillin_process(con, fillin, filename, lineno, exten, forend, exten, forstart); - fillin_free(fillin); - } else - ast_log(LOG_NOTICE, "Improper for declaration in %s around line %d!\n", filename, lineno); - arg_free(fields); - } else - ast_log(LOG_WARNING, "Syntax error in for declaration in %s around line %d!\n", filename, lineno); - - } else if (!strcasecmp(data, "break") || !strcasecmp(data, "continue")) { - struct fillin *fi; - fi = malloc(sizeof(struct fillin)); - if (fi) { - memset(fi, 0, sizeof(struct fillin)); - if (!strcasecmp(data, "break")) - fi->type = FILLIN_BREAK; - else - fi->type = FILLIN_CONTINUE; - ast_copy_string(fi->exten, exten, sizeof(fi->exten)); - fi->priority = (*pos)++; - fi->next = *fillout; - *fillout = fi; - } - } else if (match_assignment(data, &rest)) { - if (aeldebug & DEBUG_TOKENS) - ast_verbose("ASSIGN '%s' = '%s'\n", data, rest); - mlen = strlen(rest) + strlen(data) + 20; - margs = alloca(mlen); - snprintf(margs, mlen, "%s=$[ %s ]", data, rest); - app = "Set"; - if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(margs), FREE, registrar)) - ast_log(LOG_WARNING, "Unable to add assignment at priority '%d' of %s '%s'\n", *pos, what, name); - else { - *label = NULL; - (*pos)++; - } - } else { - app = data; - args = app; - while (*args && (*args > 32) && (*args != '(')) args++; - if (*args != '(') { - while(*args && (*args != '(')) { *args = '\0'; args++; }; - } - if (*args == '(') { - *args = '\0'; - args++; - /* Got arguments, trim trailing ')' */ - c = args + strlen(args) - 1; - while((c >= args) && (*c < 33) && (*c != ')')) { *c = '\0'; c--; }; - if ((c >= args) && (*c == ')')) *c = '\0'; - } else - args = ""; - ast_process_quotes_and_slashes(args, ',', '|'); - if (app[0] == '&') { - app++; - margs = alloca(strlen(args) + strlen(app) + 10); - sprintf(margs, "%s|%s", app, args); - args = margs; - app = "Macro"; - } - if (aeldebug & DEBUG_TOKENS) - ast_verbose("-- APP: '%s', ARGS: '%s'\n", app, args); - if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(args), FREE, registrar)) - ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name); - else { - (*pos)++; - *label = NULL; - } - } - return 0; -} - -static int build_step(const char *what, const char *name, const char *filename, int lineno, struct ast_context *con, char *exten, int *pos, char *data, struct fillin **fillout, char **label) -{ - struct stringlink *args, *cur; - int res=0; - struct fillin *fillin=NULL; - int dropfill = 0; - char *labelin = NULL; - if (!fillout) { - fillout = &fillin; - dropfill = 1; - } - if (!label) { - label = &labelin; - }; - args = arg_parse(data, filename, lineno); - cur = args; - while(cur) { - res |= __build_step(what, name, filename, lineno, con, exten, pos, cur->data, fillout, label); - cur = cur->next; - } - arg_free(args); - if (dropfill) { - fillin_process(con, fillin, filename, lineno, NULL, 0, NULL, 0); - fillin_free(fillin); - } - return res; -} - -static int parse_catch(char *data, char **catch, char **rest) -{ - /* Skip the word 'catch' */ - data += 5; - data = ast_skip_blanks(data); - /* Here's the extension */ - *catch = data; - if (!*data) - return 0; - while (*data && (*data > 32)) data++; - if (!*data) - return 0; - /* Trim any trailing spaces */ - *data = '\0'; - data++; - data = ast_skip_blanks(data); - if (!*data) - return 0; - *rest = data; - return 1; -} - -static void handle_macro(struct ast_context **local_contexts, struct stringlink *vars, const char *filename, int lineno) -{ - struct stringlink *argv; - struct stringlink *paramv; - struct stringlink *cur; - struct ast_context *con; - struct fillin *fillin; - char *catch, *rest; - char name[256]; - int pos; - int cpos; - - if (aeldebug & DEBUG_MACROS) - ast_verbose("Root macro def is '%s'\n", vars->data); - argv = split_token(vars->data, filename, lineno); - paramv = split_params(vars->data, filename, lineno); - if (aeldebug & DEBUG_MACROS) - ast_verbose("Found macro '%s'\n", vars->data); - snprintf(name, sizeof(name), "macro-%s", vars->data); - con = ast_context_create(local_contexts, name, registrar); - if (con) { - pos = 1; - cur = paramv; - while(cur) { - if (aeldebug & DEBUG_MACROS) - ast_verbose(" PARAM => '%s'\n", cur->data); - snprintf(name, sizeof(name), "%s=${ARG%d}", cur->data, pos); - if (ast_add_extension2(con, 0, "s", pos, NULL, NULL, "Set", strdup(name), FREE, registrar)) - ast_log(LOG_WARNING, "Unable to add step at priority '%d' of macro '%s'\n", pos, vars->data); - else - pos++; - cur = cur->next; - } - cur = argv; - while(cur) { - if (aeldebug & DEBUG_MACROS) - ast_verbose(" STEP => '%s'\n", cur->data); - if (matches_keyword(cur->data, "catch")) { - if (aeldebug & DEBUG_MACROS) - ast_verbose("--CATCH: '%s'\n", cur->data); - if (parse_catch(cur->data, &catch, &rest)) { - cpos = 1; - build_step("catch", catch, filename, lineno, con, catch, &cpos, rest, NULL, NULL); - } else - ast_log(LOG_NOTICE, "Parse error for catch at about line %d of %s\n", lineno, filename); - } else { - fillin = NULL; - build_step("macro", vars->data, filename, lineno, con, "s", &pos, cur->data, NULL, NULL); - } - cur = cur->next; - } - } else - ast_log(LOG_WARNING, "Unable to create context '%s'\n", name); - arg_free(paramv); - arg_free(argv); - if (vars->next) - ast_log(LOG_NOTICE, "Ignoring excess tokens in macro definition around line %d of %s!\n", lineno, filename); -} - -static int matches_extension(char *exten, char **extout) -{ - char *c; - *extout = NULL; - c = exten; - while(*c && (*c > 32)) c++; - if (*c) { - *c = '\0'; - c++; - c = ast_skip_blanks(c); - if (*c) { - if (*c == '=') { - *c = '\0'; - c++; - if (*c == '>') - c++; - c = ast_skip_blanks(c); - *extout = c; - return 1; - } - } - } - return 0; -} - -static void parse_keyword(char *s, char **o) -{ - char *c; - c = s; - while((*c) && (*c > 32)) c++; - if (*c) { - *c = '\0'; - c++; - c = ast_skip_blanks(c); - *o = c; - } else - *o = NULL; -} - -static void handle_context(struct ast_context **local_contexts, struct stringlink *vars, const char *filename, int lineno) -{ - struct stringlink *argv; - struct stringlink *cur2; - struct stringlink *argv2; - struct stringlink *cur; - struct ast_context *con; - char *rest; - char *c; - char name[256]; - int pos; - - if (aeldebug & DEBUG_CONTEXTS) - ast_verbose("Root context def is '%s'\n", vars->data); - argv = split_token(vars->data, filename, lineno); - if (aeldebug & DEBUG_CONTEXTS) - ast_verbose("Found context '%s'\n", vars->data); - snprintf(name, sizeof(name), "%s", vars->data); - con = ast_context_create(local_contexts, name, registrar); - if (con) { - cur = argv; - while(cur) { - if (matches_keyword(cur->data, "includes")) { - if (aeldebug & DEBUG_CONTEXTS) - ast_verbose("--INCLUDES: '%s'\n", cur->data); - parse_keyword(cur->data, &rest); - if (rest) { - argv2 = arg_parse(rest, filename, lineno); - cur2 = argv2; - while(cur2) { - ast_context_add_include2(con, cur2->data, registrar); - cur2 = cur2->next; - } - arg_free(argv2); - } - } else if (matches_keyword(cur->data, "ignorepat")) { - if (aeldebug & DEBUG_CONTEXTS) - ast_verbose("--IGNOREPAT: '%s'\n", cur->data); - parse_keyword(cur->data, &rest); - if (rest) { - argv2 = arg_parse(rest, filename, lineno); - cur2 = argv2; - while(cur2) { - ast_context_add_ignorepat2(con, cur2->data, registrar); - cur2 = cur2->next; - } - arg_free(argv2); - } - } else if (matches_keyword(cur->data, "switches") || matches_keyword(cur->data, "eswitches")) { - if (aeldebug & DEBUG_CONTEXTS) - ast_verbose("--[E]SWITCH: '%s'\n", cur->data); - parse_keyword(cur->data, &rest); - if (rest) { - argv2 = arg_parse(rest, filename, lineno); - cur2 = argv2; - while(cur2) { - c = strchr(cur2->data, '/'); - if (c) { - *c = '\0'; - c++; - } else - c = ""; - ast_context_add_switch2(con, cur2->data, c, (cur->data[0] == 'e'), registrar); - cur2 = cur2->next; - } - arg_free(argv2); - } - } else if (matches_extension(cur->data, &rest)) { - if (aeldebug & DEBUG_CONTEXTS) - ast_verbose("Extension: '%s' => '%s'\n", cur->data, rest); - pos = 1; - build_step("extension", cur->data, filename, lineno, con, cur->data, &pos, rest, NULL, NULL); - } - cur = cur->next; - } - } else - ast_log(LOG_WARNING, "Unable to create context '%s'\n", name); - arg_free(argv); - if (vars->next) - ast_log(LOG_NOTICE, "Ignoring excess tokens in macro definition around line %d of %s!\n", lineno, filename); -} - -static int handle_root_token(struct ast_context **local_contexts, char *token, int level, const char *filename, int lineno) -{ - struct stringlink *argv, *cur; - argv = split_token(token, filename, lineno); - if (aeldebug & DEBUG_TOKENS) { - ast_verbose("Found root token '%s' at level %d (%s:%d)!\n", token, level, filename, lineno); - cur = argv; - while(cur) { - ast_verbose(" ARG => '%s'\n", cur->data); - cur = cur->next; - } - } - if (!strcasecmp(token, "globals")) { - handle_globals(argv); - } else if (!strcasecmp(token, "macro")) { - handle_macro(local_contexts, argv, filename, lineno); - } else if (!strcasecmp(token, "context")) { - handle_context(local_contexts, argv, filename, lineno); - } else { - ast_log(LOG_NOTICE, "Unknown root token '%s'\n", token); - } - arg_free(argv); - return 0; -} - - -static int ast_ael_compile(struct ast_context **local_contexts, const char *filename) -{ - char *rfilename; - char *buf, *tbuf; - int bufsiz; - FILE *f; - char *c; - char *token; - int lineno=0; - - if (filename[0] == '/') - rfilename = (char *)filename; - else { - rfilename = alloca(strlen(filename) + strlen(ast_config_AST_CONFIG_DIR) + 2); - sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, filename); - } - - f = fopen(rfilename, "r"); - if (!f) { - ast_log(LOG_WARNING, "Unable to open '%s': %s\n", rfilename, strerror(errno)); - return -1; - } - buf = malloc(4096); - if (!buf) { - ast_log(LOG_WARNING, "Out of memory!\n"); - fclose(f); - return -1; - } - buf[0] = 0; - bufsiz = 4096; - while(!feof(f)) { - if (bufsiz - strlen(buf) < 2048) { - bufsiz += 4096; - tbuf = realloc(buf, bufsiz); - if (tbuf) { - buf = tbuf; - } else { - free(buf); - ast_log(LOG_WARNING, "Out of memory!\n"); - fclose(f); - } - } - if (fgets(buf + strlen(buf), bufsiz - strlen(buf), f)) { - lineno++; - while(*buf && buf[strlen(buf) - 1] < 33) - buf[strlen(buf) - 1] = '\0'; - c = strstr(buf, "//"); - if (c) - *c = '\0'; - if (*buf) { - if (aeldebug & DEBUG_READ) - ast_verbose("Newly composed line '%s'\n", buf); - while((token = grab_token(buf, filename, lineno))) { - handle_root_token(local_contexts, token, 0, filename, lineno); - free(token); - } - } - } - }; - free(buf); - fclose(f); - return 0; -} - -static int pbx_load_module(void) -{ - struct ast_context *local_contexts=NULL, *con; - ast_ael_compile(&local_contexts, config); - ast_merge_contexts_and_delete(&local_contexts, registrar); - for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con)) - ast_context_verify_includes(con); - - return 0; -} - -/* CLI interface */ -static int ael_debug_read(int fd, int argc, char *argv[]) -{ - aeldebug |= DEBUG_READ; - return 0; -} - -static int ael_debug_tokens(int fd, int argc, char *argv[]) -{ - aeldebug |= DEBUG_TOKENS; - return 0; -} - -static int ael_debug_macros(int fd, int argc, char *argv[]) -{ - aeldebug |= DEBUG_MACROS; - return 0; -} - -static int ael_debug_contexts(int fd, int argc, char *argv[]) -{ - aeldebug |= DEBUG_CONTEXTS; - return 0; -} - -static int ael_no_debug(int fd, int argc, char *argv[]) -{ - aeldebug = 0; - return 0; -} - -static int ael_reload(int fd, int argc, char *argv[]) -{ - ast_context_destroy(NULL, registrar); - return (pbx_load_module()); -} - -static struct ast_cli_entry ael_cli[] = { - { { "ael", "reload", NULL }, ael_reload, "Reload AEL configuration"}, - { { "ael", "debug", "read", NULL }, ael_debug_read, "Enable AEL read debug"}, - { { "ael", "debug", "tokens", NULL }, ael_debug_tokens, "Enable AEL tokens debug"}, - { { "ael", "debug", "macros", NULL }, ael_debug_macros, "Enable AEL macros debug"}, - { { "ael", "debug", "contexts", NULL }, ael_debug_contexts, "Enable AEL contexts debug"}, - { { "ael", "no", "debug", NULL }, ael_no_debug, "Disable AEL debug messages"}, -}; - -/* - * Standard module functions ... - */ -int unload_module(void) -{ - ast_context_destroy(NULL, registrar); - ast_cli_unregister_multiple(ael_cli, sizeof(ael_cli)/ sizeof(ael_cli[0])); - return 0; -} - - -int load_module(void) -{ - ast_cli_register_multiple(ael_cli, sizeof(ael_cli)/ sizeof(ael_cli[0])); - return (pbx_load_module()); -} - -int reload(void) -{ - ast_context_destroy(NULL, registrar); - return pbx_load_module(); -} - -int usecount(void) -{ - return 0; -} - -char *description(void) -{ - return dtext; -} - -char *key(void) -{ - return ASTERISK_GPL_KEY; -} diff --git a/1.2-netsec/pbx/pbx_config.c b/1.2-netsec/pbx/pbx_config.c deleted file mode 100644 index 42e43470a..000000000 --- a/1.2-netsec/pbx/pbx_config.c +++ /dev/null @@ -1,1831 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief Populate and remember extensions from static config file - * - * - */ - -#include <sys/types.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <errno.h> - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/pbx.h" -#include "asterisk/config.h" -#include "asterisk/options.h" -#include "asterisk/module.h" -#include "asterisk/logger.h" -#include "asterisk/cli.h" -#include "asterisk/callerid.h" - -#ifdef __AST_DEBUG_MALLOC -static void FREE(void *ptr) -{ - free(ptr); -} -#else -#define FREE free -#endif - -static char *dtext = "Text Extension Configuration"; -static char *config = "extensions.conf"; -static char *registrar = "pbx_config"; - -static int static_config = 0; -static int write_protect_config = 1; -static int autofallthrough_config = 0; -static int clearglobalvars_config = 0; - -AST_MUTEX_DEFINE_STATIC(save_dialplan_lock); - -static struct ast_context *local_contexts = NULL; - -/* - * Help for commands provided by this module ... - */ -static char context_dont_include_help[] = -"Usage: dont include <context> in <context>\n" -" Remove an included context from another context.\n"; - -static char context_remove_extension_help[] = -"Usage: remove extension exten@context [priority]\n" -" Remove an extension from a given context. If a priority\n" -" is given, only that specific priority from the given extension\n" -" will be removed.\n"; - -static char context_add_include_help[] = -"Usage: include <context> in <context>\n" -" Include a context in another context.\n"; - -static char save_dialplan_help[] = -"Usage: save dialplan [/path/to/extension/file]\n" -" Save dialplan created by pbx_config module.\n" -"\n" -"Example: save dialplan (/etc/asterisk/extensions.conf)\n" -" save dialplan /home/markster (/home/markster/extensions.conf)\n"; - -static char context_add_extension_help[] = -"Usage: add extension <exten>,<priority>,<app>,<app-data> into <context>\n" -" [replace]\n\n" -" This command will add new extension into <context>. If there is an\n" -" existence of extension with the same priority and last 'replace'\n" -" arguments is given here we simply replace this extension.\n" -"\n" -"Example: add extension 6123,1,Dial,IAX/216.207.245.56/6123 into local\n" -" Now, you can dial 6123 and talk to Markster :)\n"; - -static char context_add_ignorepat_help[] = -"Usage: add ignorepat <pattern> into <context>\n" -" This command adds a new ignore pattern into context <context>\n" -"\n" -"Example: add ignorepat _3XX into local\n"; - -static char context_remove_ignorepat_help[] = -"Usage: remove ignorepat <pattern> from <context>\n" -" This command removes an ignore pattern from context <context>\n" -"\n" -"Example: remove ignorepat _3XX from local\n"; - -static char reload_extensions_help[] = -"Usage: reload extensions.conf without reloading any other modules\n" -" This command does not delete global variables unless\n" -" clearglobalvars is set to yes in extensions.conf\n" -"\n" -"Example: extensions reload\n"; - -/* - * Implementation of functions provided by this module - */ - -/*! - * REMOVE INCLUDE command stuff - */ -static int handle_context_dont_include(int fd, int argc, char *argv[]) -{ - if (argc != 5) - return RESULT_SHOWUSAGE; - - if (strcmp(argv[3], "in")) - return RESULT_SHOWUSAGE; - - if (!ast_context_remove_include(argv[4], argv[2], registrar)) { - ast_cli(fd, "We are not including '%s' in '%s' now\n", - argv[2], argv[4]); - return RESULT_SUCCESS; - } - - ast_cli(fd, "Failed to remove '%s' include from '%s' context\n", - argv[2], argv[4]); - return RESULT_FAILURE; -} - -static char *complete_context_dont_include(char *line, char *word, - int pos, int state) -{ - int which = 0; - - /* - * Context completion ... - */ - if (pos == 2) { - struct ast_context *c; - - if (ast_lock_contexts()) { - ast_log(LOG_ERROR, "Failed to lock context list\n"); - return NULL; - } - - /* walk pbx_get_contexts ... */ - c = ast_walk_contexts(NULL); - while (c) { - struct ast_include *i; - - if (ast_lock_context(c)) { - c = ast_walk_contexts(c); - continue; - } - - i = ast_walk_context_includes(c, NULL); - while (i) { - if (!strlen(word) || - !strncmp(ast_get_include_name(i), word, strlen(word))) { - struct ast_context *nc; - int already_served = 0; - - /* check if this include is already served or not */ - - /* go through all contexts again till we reach actuall - * context or already_served = 1 - */ - nc = ast_walk_contexts(NULL); - while (nc && nc != c && !already_served) { - if (!ast_lock_context(nc)) { - struct ast_include *ni; - - ni = ast_walk_context_includes(nc, NULL); - while (ni && !already_served) { - if (!strcmp(ast_get_include_name(i), - ast_get_include_name(ni))) - already_served = 1; - ni = ast_walk_context_includes(nc, ni); - } - - ast_unlock_context(nc); - } - nc = ast_walk_contexts(nc); - } - - if (!already_served) { - if (++which > state) { - char *res = - strdup(ast_get_include_name(i)); - ast_unlock_context(c); - ast_unlock_contexts(); - return res; - } - } - } - i = ast_walk_context_includes(c, i); - } - - ast_unlock_context(c); - c = ast_walk_contexts(c); - } - - ast_unlock_contexts(); - return NULL; - } - - /* - * 'in' completion ... (complete only if previous context is really - * included somewhere) - */ - if (pos == 3) { - struct ast_context *c; - char *context, *dupline, *duplinet; - - if (state > 0) return NULL; - - /* take 'context' from line ... */ - if (!(dupline = strdup(line))) { - ast_log(LOG_ERROR, "Out of free memory\n"); - return NULL; - } - - duplinet = dupline; - strsep(&duplinet, " "); /* skip 'dont' */ - strsep(&duplinet, " "); /* skip 'include' */ - context = strsep(&duplinet, " "); - - if (!context) { - free(dupline); - return NULL; - } - - if (ast_lock_contexts()) { - ast_log(LOG_WARNING, "Failed to lock contexts list\n"); - free(dupline); - return NULL; - } - - /* go through all contexts and check if is included ... */ - c = ast_walk_contexts(NULL); - while (c) { - struct ast_include *i; - if (ast_lock_context(c)) { - free(dupline); - ast_unlock_contexts(); - return NULL; - } - - i = ast_walk_context_includes(c, NULL); - while (i) { - /* is it our context? */ - if (!strcmp(ast_get_include_name(i), context)) { - /* yes, it is, context is really included, so - * complete "in" command - */ - free(dupline); - ast_unlock_context(c); - ast_unlock_contexts(); - return strdup("in"); - } - i = ast_walk_context_includes(c, i); - } - ast_unlock_context(c); - c = ast_walk_contexts(c); - } - free(dupline); - ast_unlock_contexts(); - return NULL; - } - - /* - * Context from which we removing include ... - */ - if (pos == 4) { - struct ast_context *c; - char *context, *dupline, *duplinet, *in; - - if (!(dupline = strdup(line))) { - ast_log(LOG_ERROR, "Out of free memory\n"); - return NULL; - } - - duplinet = dupline; - - strsep(&duplinet, " "); /* skip 'dont' */ - strsep(&duplinet, " "); /* skip 'include' */ - - if (!(context = strsep(&duplinet, " "))) { - free(dupline); - return NULL; - } - - /* third word must be in */ - in = strsep(&duplinet, " "); - if (!in || - strcmp(in, "in")) { - free(dupline); - return NULL; - } - - if (ast_lock_contexts()) { - ast_log(LOG_ERROR, "Failed to lock context list\n"); - free(dupline); - return NULL; - } - - /* walk through all contexts ... */ - c = ast_walk_contexts(NULL); - while (c) { - struct ast_include *i; - if (ast_lock_context(c)) { - free(dupline); - return NULL; - } - - /* walk through all includes and check if it is our context */ - i = ast_walk_context_includes(c, NULL); - while (i) { - /* is in this context included another on which we want to - * remove? - */ - if (!strcmp(context, ast_get_include_name(i))) { - /* yes, it's included, is matching our word too? */ - if (!strncmp(ast_get_context_name(c), - word, strlen(word))) { - /* check state for completion */ - if (++which > state) { - char *res = strdup(ast_get_context_name(c)); - free(dupline); - ast_unlock_context(c); - ast_unlock_contexts(); - return res; - } - } - break; - } - i = ast_walk_context_includes(c, i); - } - ast_unlock_context(c); - c = ast_walk_contexts(c); - } - - free(dupline); - ast_unlock_contexts(); - return NULL; - } - - return NULL; -} - -/*! - * REMOVE EXTENSION command stuff - */ -static int handle_context_remove_extension(int fd, int argc, char *argv[]) -{ - int removing_priority = 0; - char *exten, *context; - - if (argc != 4 && argc != 3) return RESULT_SHOWUSAGE; - - /* - * Priority input checking ... - */ - if (argc == 4) { - char *c = argv[3]; - - /* check for digits in whole parameter for right priority ... - * why? because atoi (strtol) returns 0 if any characters in - * string and whole extension will be removed, it's not good - */ - if (strcmp("hint", c)) { - while (*c != '\0') { - if (!isdigit(*c++)) { - ast_cli(fd, "Invalid priority '%s'\n", argv[3]); - return RESULT_FAILURE; - } - } - removing_priority = atoi(argv[3]); - } else - removing_priority = PRIORITY_HINT; - - if (removing_priority == 0) { - ast_cli(fd, "If you want to remove whole extension, please " \ - "omit priority argument\n"); - return RESULT_FAILURE; - } - } - - /* - * Format exten@context checking ... - */ - if (!(context = strchr(argv[2], (int)'@'))) { - ast_cli(fd, "First argument must be in exten@context format\n"); - return RESULT_FAILURE; - } - - *context++ = '\0'; - exten = argv[2]; - if ((!strlen(exten)) || (!(strlen(context)))) { - ast_cli(fd, "Missing extension or context name in second argument '%s@%s'\n", - exten == NULL ? "?" : exten, context == NULL ? "?" : context); - return RESULT_FAILURE; - } - - if (!ast_context_remove_extension(context, exten, removing_priority, registrar)) { - if (!removing_priority) - ast_cli(fd, "Whole extension %s@%s removed\n", - exten, context); - else - ast_cli(fd, "Extension %s@%s with priority %d removed\n", - exten, context, removing_priority); - - return RESULT_SUCCESS; - } - - ast_cli(fd, "Failed to remove extension %s@%s\n", exten, context); - - return RESULT_FAILURE; -} - -#define BROKEN_READLINE 1 - -#ifdef BROKEN_READLINE -/* - * There is one funny thing, when you have word like 300@ and you hit - * <tab>, you arguments will like as your word is '300 ', so it '@' - * characters acts sometimes as word delimiter and sometimes as a part - * of word - * - * This fix function, allocates new word variable and store here every - * time xxx@yyy always as one word and correct pos is set too - * - * It's ugly, I know, but I'm waiting for Mark suggestion if upper is - * bug or feature ... - */ -static int fix_complete_args(char *line, char **word, int *pos) -{ - char *_line, *_strsep_line, *_previous_word = NULL, *_word = NULL; - int words = 0; - - _line = strdup(line); - - _strsep_line = _line; - while (_strsep_line) { - _previous_word = _word; - _word = strsep(&_strsep_line, " "); - - if (_word && strlen(_word)) words++; - } - - - if (_word || _previous_word) { - if (_word) { - if (!strlen(_word)) words++; - *word = strdup(_word); - } else - *word = strdup(_previous_word); - *pos = words - 1; - free(_line); - return 0; - } - - free(_line); - return -1; -} -#endif /* BROKEN_READLINE */ - -static char *complete_context_remove_extension(char *line, char *word, int pos, - int state) -{ - char *ret = NULL; - int which = 0; - -#ifdef BROKEN_READLINE - /* - * Fix arguments, *word is a new allocated structure, REMEMBER to - * free *word when you want to return from this function ... - */ - if (fix_complete_args(line, &word, &pos)) { - ast_log(LOG_ERROR, "Out of free memory\n"); - return NULL; - } -#endif - - /* - * exten@context completion ... - */ - if (pos == 2) { - struct ast_context *c; - struct ast_exten *e; - char *context = NULL, *exten = NULL, *delim = NULL; - - /* now, parse values from word = exten@context */ - if ((delim = strchr(word, (int)'@'))) { - /* check for duplicity ... */ - if (delim != strrchr(word, (int)'@')) { -#ifdef BROKEN_READLINE - free(word); -#endif - return NULL; - } - - *delim = '\0'; - exten = strdup(word); - context = strdup(delim + 1); - *delim = '@'; - } else { - exten = strdup(word); - } -#ifdef BROKEN_READLINE - free(word); -#endif - - if (ast_lock_contexts()) { - ast_log(LOG_ERROR, "Failed to lock context list\n"); - free(context); free(exten); - return NULL; - } - - /* find our context ... */ - c = ast_walk_contexts(NULL); - while (c) { - /* our context? */ - if ( (!context || !strlen(context)) || /* if no input, all contexts ... */ - (context && !strncmp(ast_get_context_name(c), - context, strlen(context))) ) { /* if input, compare ... */ - /* try to complete extensions ... */ - e = ast_walk_context_extensions(c, NULL); - while (e) { - /* our extension? */ - if ( (!exten || !strlen(exten)) || /* if not input, all extensions ... */ - (exten && !strncmp(ast_get_extension_name(e), exten, - strlen(exten))) ) { /* if input, compare ... */ - if (++which > state) { - /* If there is an extension then return - * exten@context. - */ - if (exten) { - ret = malloc(strlen(ast_get_extension_name(e)) + - strlen(ast_get_context_name(c)) + 2); - if (ret) - sprintf(ret, "%s@%s", ast_get_extension_name(e), - ast_get_context_name(c)); - } - free(exten); free(context); - - ast_unlock_contexts(); - - return ret; - } - } - e = ast_walk_context_extensions(c, e); - } - } - c = ast_walk_contexts(c); - } - - ast_unlock_contexts(); - - free(exten); free(context); - - return NULL; - } - - /* - * Complete priority ... - */ - if (pos == 3) { - char *delim, *exten, *context, *dupline, *duplinet, *ec; - struct ast_context *c; - - dupline = strdup(line); - if (!dupline) { -#ifdef BROKEN_READLINE - free(word); -#endif - return NULL; - } - duplinet = dupline; - - strsep(&duplinet, " "); /* skip 'remove' */ - strsep(&duplinet, " "); /* skip 'extension */ - - if (!(ec = strsep(&duplinet, " "))) { - free(dupline); -#ifdef BROKEN_READLINE - free(word); -#endif - return NULL; - } - - /* wrong exten@context format? */ - if (!(delim = strchr(ec, (int)'@')) || - (strchr(ec, (int)'@') != strrchr(ec, (int)'@'))) { -#ifdef BROKEN_READLINE - free(word); -#endif - free(dupline); - return NULL; - } - - /* check if there is exten and context too ... */ - *delim = '\0'; - if ((!strlen(ec)) || (!strlen(delim + 1))) { -#ifdef BROKEN_READLINE - free(word); -#endif - free(dupline); - return NULL; - } - - exten = strdup(ec); - context = strdup(delim + 1); - free(dupline); - - if (ast_lock_contexts()) { - ast_log(LOG_ERROR, "Failed to lock context list\n"); -#ifdef BROKEN_READLINE - free(word); -#endif - free(exten); free(context); - return NULL; - } - - /* walk contexts */ - c = ast_walk_contexts(NULL); - while (c) { - if (!strcmp(ast_get_context_name(c), context)) { - struct ast_exten *e; - - /* walk extensions */ - free(context); - e = ast_walk_context_extensions(c, NULL); - while (e) { - if (!strcmp(ast_get_extension_name(e), exten)) { - struct ast_exten *priority; - char buffer[10]; - - free(exten); - priority = ast_walk_extension_priorities(e, NULL); - /* serve priorities */ - do { - snprintf(buffer, 10, "%u", - ast_get_extension_priority(priority)); - if (!strncmp(word, buffer, strlen(word))) { - if (++which > state) { -#ifdef BROKEN_READLINE - free(word); -#endif - ast_unlock_contexts(); - return strdup(buffer); - } - } - priority = ast_walk_extension_priorities(e, - priority); - } while (priority); - -#ifdef BROKEN_READLINE - free(word); -#endif - ast_unlock_contexts(); - return NULL; - } - e = ast_walk_context_extensions(c, e); - } -#ifdef BROKEN_READLINE - free(word); -#endif - free(exten); - ast_unlock_contexts(); - return NULL; - } - c = ast_walk_contexts(c); - } - -#ifdef BROKEN_READLINE - free(word); -#endif - free(exten); free(context); - - ast_unlock_contexts(); - return NULL; - } - -#ifdef BROKEN_READLINE - free(word); -#endif - return NULL; -} - -/*! - * Include context ... - */ -static int handle_context_add_include(int fd, int argc, char *argv[]) -{ - if (argc != 5) return RESULT_SHOWUSAGE; - - /* third arg must be 'in' ... */ - if (strcmp(argv[3], "in") && strcmp(argv[3], "into")) return RESULT_SHOWUSAGE; - - if (ast_context_add_include(argv[4], argv[2], registrar)) { - switch (errno) { - case ENOMEM: - ast_cli(fd, "Out of memory for context addition\n"); break; - - case EBUSY: - ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); break; - - case EEXIST: - ast_cli(fd, "Context '%s' already included in '%s' context\n", - argv[2], argv[4]); break; - - case ENOENT: - case EINVAL: - ast_cli(fd, "There is no existence of context '%s'\n", - errno == ENOENT ? argv[4] : argv[2]); break; - - default: - ast_cli(fd, "Failed to include '%s' in '%s' context\n", - argv[2], argv[4]); break; - } - return RESULT_FAILURE; - } - - /* show some info ... */ - ast_cli(fd, "Context '%s' included in '%s' context\n", - argv[2], argv[4]); - - return RESULT_SUCCESS; -} - -static char *complete_context_add_include(char *line, char *word, int pos, - int state) -{ - struct ast_context *c; - int which = 0; - - /* server context for inclusion ... */ - if (pos == 1) - { - if (ast_lock_contexts()) { - ast_log(LOG_ERROR, "Failed to lock context list\n"); - return NULL; - } - - /* server all contexts */ - c = ast_walk_contexts(NULL); - while (c) { - if ((!strlen(word) || - !strncmp(ast_get_context_name(c), word, strlen(word))) && - ++which > state) - { - char *context = strdup(ast_get_context_name(c)); - ast_unlock_contexts(); - return context; - } - c = ast_walk_contexts(c); - } - - ast_unlock_contexts(); - } - - /* complete 'in' only if context exist ... */ - if (pos == 2) - { - char *context, *dupline, *duplinet; - - if (state != 0) return NULL; - - /* parse context from line ... */ - if (!(dupline = strdup(line))) { - ast_log(LOG_ERROR, "Out of free memory\n"); - if (state == 0) return strdup("in"); - return NULL; - } - - duplinet = dupline; - - strsep(&duplinet, " "); - context = strsep(&duplinet, " "); - if (context) { - struct ast_context *c; - int context_existence = 0; - - /* check for context existence ... */ - if (ast_lock_contexts()) { - ast_log(LOG_ERROR, "Failed to lock context list\n"); - free(dupline); - /* our fault, we can't check, so complete 'in' ... */ - return strdup("in"); - } - - c = ast_walk_contexts(NULL); - while (c && !context_existence) { - if (!strcmp(context, ast_get_context_name(c))) { - context_existence = 1; - continue; - } - c = ast_walk_contexts(c); - } - - /* if context exists, return 'into' ... */ - if (context_existence) { - free(dupline); - ast_unlock_contexts(); - return strdup("into"); - } - - ast_unlock_contexts(); - } - - free(dupline); - return NULL; - } - - /* serve context into which we include another context */ - if (pos == 3) - { - char *context, *dupline, *duplinet, *in; - int context_existence = 0; - - if (!(dupline = strdup(line))) { - ast_log(LOG_ERROR, "Out of free memory\n"); - return NULL; - } - - duplinet = dupline; - - strsep(&duplinet, " "); /* skip 'include' */ - context = strsep(&duplinet, " "); - in = strsep(&duplinet, " "); - - /* given some context and third word is in? */ - if (!strlen(context) || strcmp(in, "in")) { - free(dupline); - return NULL; - } - - if (ast_lock_contexts()) { - ast_log(LOG_ERROR, "Failed to lock context list\n"); - free(dupline); - return NULL; - } - - /* check for context existence ... */ - c = ast_walk_contexts(NULL); - while (c && !context_existence) { - if (!strcmp(context, ast_get_context_name(c))) { - context_existence = 1; - continue; - } - c = ast_walk_contexts(c); - } - - if (!context_existence) { - free(dupline); - ast_unlock_contexts(); - return NULL; - } - - /* go through all contexts ... */ - c = ast_walk_contexts(NULL); - while (c) { - /* must be different contexts ... */ - if (strcmp(context, ast_get_context_name(c))) { - if (!ast_lock_context(c)) { - struct ast_include *i; - int included = 0; - - /* check for duplicity inclusion ... */ - i = ast_walk_context_includes(c, NULL); - while (i && !included) { - if (!strcmp(ast_get_include_name(i), context)) - included = 1; - i = ast_walk_context_includes(c, i); - } - ast_unlock_context(c); - - /* not included yet, so show possibility ... */ - if (!included && - !strncmp(ast_get_context_name(c), word, strlen(word))){ - - if (++which > state) { - char *res = strdup(ast_get_context_name(c)); - free(dupline); - ast_unlock_contexts(); - return res; - } - } - } - } - c = ast_walk_contexts(c); - } - - ast_unlock_contexts(); - free(dupline); - return NULL; - } - - return NULL; -} - -/*! - * \brief 'save dialplan' CLI command implementation functions ... - */ -static int handle_save_dialplan(int fd, int argc, char *argv[]) -{ - char filename[256]; - struct ast_context *c; - struct ast_config *cfg; - struct ast_variable *v; - int context_header_written; - int incomplete = 0; /* incomplete config write? */ - FILE *output; - - if (! (static_config && !write_protect_config)) { - ast_cli(fd, - "I can't save dialplan now, see '%s' example file.\n", - config); - return RESULT_FAILURE; - } - - if (argc != 2 && argc != 3) return RESULT_SHOWUSAGE; - - if (ast_mutex_lock(&save_dialplan_lock)) { - ast_cli(fd, - "Failed to lock dialplan saving (another proccess saving?)\n"); - return RESULT_FAILURE; - } - - /* have config path? */ - if (argc == 3) { - /* is there extension.conf too? */ - if (!strstr(argv[2], ".conf")) { - /* no, only directory path, check for last '/' occurence */ - if (*(argv[2] + strlen(argv[2]) -1) == '/') - snprintf(filename, sizeof(filename), "%s%s", - argv[2], config); - else - /* without config extensions.conf, add it */ - snprintf(filename, sizeof(filename), "%s/%s", - argv[2], config); - } else - /* there is an .conf */ - snprintf(filename, sizeof(filename), argv[2]); - } else - /* no config file, default one */ - snprintf(filename, sizeof(filename), "%s/%s", - (char *)ast_config_AST_CONFIG_DIR, config); - - cfg = ast_config_load("extensions.conf"); - - /* try to lock contexts list */ - if (ast_lock_contexts()) { - ast_cli(fd, "Failed to lock contexts list\n"); - ast_mutex_unlock(&save_dialplan_lock); - ast_config_destroy(cfg); - return RESULT_FAILURE; - } - - /* create new file ... */ - if (!(output = fopen(filename, "wt"))) { - ast_cli(fd, "Failed to create file '%s'\n", - filename); - ast_unlock_contexts(); - ast_mutex_unlock(&save_dialplan_lock); - ast_config_destroy(cfg); - return RESULT_FAILURE; - } - - /* fireout general info */ - fprintf(output, "[general]\nstatic=%s\nwriteprotect=%s\n\n", - static_config ? "yes" : "no", - write_protect_config ? "yes" : "no"); - - if ((v = ast_variable_browse(cfg, "globals"))) { - fprintf(output, "[globals]\n"); - while(v) { - fprintf(output, "%s => %s\n", v->name, v->value); - v = v->next; - } - fprintf(output, "\n"); - } - - ast_config_destroy(cfg); - - /* walk all contexts */ - c = ast_walk_contexts(NULL); - while (c) { - context_header_written = 0; - - /* try to lock context and fireout all info */ - if (!ast_lock_context(c)) { - struct ast_exten *e, *last_written_e = NULL; - struct ast_include *i; - struct ast_ignorepat *ip; - struct ast_sw *sw; - - /* registered by this module? */ - if (!strcmp(ast_get_context_registrar(c), registrar)) { - fprintf(output, "[%s]\n", ast_get_context_name(c)); - context_header_written = 1; - } - - /* walk extensions ... */ - e = ast_walk_context_extensions(c, NULL); - while (e) { - struct ast_exten *p; - - /* fireout priorities */ - p = ast_walk_extension_priorities(e, NULL); - while (p) { - if (!strcmp(ast_get_extension_registrar(p), - registrar)) { - - /* make empty line between different extensions */ - if (last_written_e != NULL && - strcmp(ast_get_extension_name(last_written_e), - ast_get_extension_name(p))) - fprintf(output, "\n"); - last_written_e = p; - - if (!context_header_written) { - fprintf(output, "[%s]\n", ast_get_context_name(c)); - context_header_written = 1; - } - - if (ast_get_extension_priority(p)!=PRIORITY_HINT) { - char *tempdata = NULL, *startdata; - tempdata = strdup((char *)ast_get_extension_app_data(p)); - if (tempdata) { - startdata = tempdata; - while (*tempdata) { - if (*tempdata == '|') - *tempdata = ','; - tempdata++; - } - tempdata = startdata; - } - if (ast_get_extension_matchcid(p)) - fprintf(output, "exten => %s/%s,%d,%s(%s)\n", - ast_get_extension_name(p), - ast_get_extension_cidmatch(p), - ast_get_extension_priority(p), - ast_get_extension_app(p), - tempdata); - else - fprintf(output, "exten => %s,%d,%s(%s)\n", - ast_get_extension_name(p), - ast_get_extension_priority(p), - ast_get_extension_app(p), - tempdata); - if (tempdata) - free(tempdata); - } else - fprintf(output, "exten => %s,hint,%s\n", - ast_get_extension_name(p), - ast_get_extension_app(p)); - - } - p = ast_walk_extension_priorities(e, p); - } - - e = ast_walk_context_extensions(c, e); - } - - /* written any extensions? ok, write space between exten & inc */ - if (last_written_e) fprintf(output, "\n"); - - /* walk through includes */ - i = ast_walk_context_includes(c, NULL); - while (i) { - if (!strcmp(ast_get_include_registrar(i), registrar)) { - if (!context_header_written) { - fprintf(output, "[%s]\n", ast_get_context_name(c)); - context_header_written = 1; - } - fprintf(output, "include => %s\n", - ast_get_include_name(i)); - } - i = ast_walk_context_includes(c, i); - } - - if (ast_walk_context_includes(c, NULL)) - fprintf(output, "\n"); - - /* walk through switches */ - sw = ast_walk_context_switches(c, NULL); - while (sw) { - if (!strcmp(ast_get_switch_registrar(sw), registrar)) { - if (!context_header_written) { - fprintf(output, "[%s]\n", ast_get_context_name(c)); - context_header_written = 1; - } - fprintf(output, "switch => %s/%s\n", - ast_get_switch_name(sw), - ast_get_switch_data(sw)); - } - sw = ast_walk_context_switches(c, sw); - } - - if (ast_walk_context_switches(c, NULL)) - fprintf(output, "\n"); - - /* fireout ignorepats ... */ - ip = ast_walk_context_ignorepats(c, NULL); - while (ip) { - if (!strcmp(ast_get_ignorepat_registrar(ip), registrar)) { - if (!context_header_written) { - fprintf(output, "[%s]\n", ast_get_context_name(c)); - context_header_written = 1; - } - - fprintf(output, "ignorepat => %s\n", - ast_get_ignorepat_name(ip)); - } - ip = ast_walk_context_ignorepats(c, ip); - } - - ast_unlock_context(c); - } else - incomplete = 1; - - c = ast_walk_contexts(c); - } - - ast_unlock_contexts(); - ast_mutex_unlock(&save_dialplan_lock); - fclose(output); - - if (incomplete) { - ast_cli(fd, "Saved dialplan is incomplete\n"); - return RESULT_FAILURE; - } - - ast_cli(fd, "Dialplan successfully saved into '%s'\n", - filename); - return RESULT_SUCCESS; -} - -/*! - * \brief ADD EXTENSION command stuff - */ -static int handle_context_add_extension(int fd, int argc, char *argv[]) -{ - char *whole_exten; - char *exten, *prior; - int iprior = -2; - char *cidmatch, *app, *app_data; - char *start, *end; - - /* check for arguments at first */ - if (argc != 5 && argc != 6) return RESULT_SHOWUSAGE; - if (strcmp(argv[3], "into")) return RESULT_SHOWUSAGE; - if (argc == 6) if (strcmp(argv[5], "replace")) return RESULT_SHOWUSAGE; - - whole_exten = argv[2]; - exten = strsep(&whole_exten,","); - if (strchr(exten, '/')) { - cidmatch = exten; - strsep(&cidmatch,"/"); - } else { - cidmatch = NULL; - } - prior = strsep(&whole_exten,","); - if (prior) { - if (!strcmp(prior, "hint")) { - iprior = PRIORITY_HINT; - } else { - if (sscanf(prior, "%d", &iprior) != 1) { - ast_cli(fd, "'%s' is not a valid priority\n", prior); - prior = NULL; - } - } - } - app = whole_exten; - if (app && (start = strchr(app, '(')) && (end = strrchr(app, ')'))) { - *start = *end = '\0'; - app_data = start + 1; - ast_process_quotes_and_slashes(app_data, ',', '|'); - } else { - if (app) { - app_data = strchr(app, ','); - if (app_data) { - *app_data = '\0'; - app_data++; - } - } else - app_data = NULL; - } - - if (!exten || !prior || !app || (!app_data && iprior != PRIORITY_HINT)) return RESULT_SHOWUSAGE; - - if (!app_data) - app_data=""; - if (ast_add_extension(argv[4], argc == 6 ? 1 : 0, exten, iprior, NULL, cidmatch, app, - (void *)strdup(app_data), free, registrar)) { - switch (errno) { - case ENOMEM: - ast_cli(fd, "Out of free memory\n"); break; - - case EBUSY: - ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); break; - - case ENOENT: - ast_cli(fd, "No existence of '%s' context\n", argv[4]); break; - - case EEXIST: - ast_cli(fd, "Extension %s@%s with priority %s already exists\n", - exten, argv[4], prior); break; - - default: - ast_cli(fd, "Failed to add '%s,%s,%s,%s' extension into '%s' context\n", - exten, prior, app, app_data, argv[4]); break; - } - return RESULT_FAILURE; - } - - if (argc == 6) - ast_cli(fd, "Extension %s@%s (%s) replace by '%s,%s,%s,%s'\n", - exten, argv[4], prior, exten, prior, app, app_data); - else - ast_cli(fd, "Extension '%s,%s,%s,%s' added into '%s' context\n", - exten, prior, app, app_data, argv[4]); - - return RESULT_SUCCESS; -} - -/*! add extension 6123,1,Dial,IAX/212.71.138.13/6123 into local */ -static char *complete_context_add_extension(char *line, char *word, - int pos, int state) -{ - int which = 0; - - /* complete 'into' word ... */ - if (pos == 3) { - if (state == 0) return strdup("into"); - return NULL; - } - - /* complete context */ - if (pos == 4) { - struct ast_context *c; - - /* try to lock contexts list ... */ - if (ast_lock_contexts()) { - ast_log(LOG_WARNING, "Failed to lock contexts list\n"); - return NULL; - } - - /* walk through all contexts */ - c = ast_walk_contexts(NULL); - while (c) { - /* matching context? */ - if (!strncmp(ast_get_context_name(c), word, strlen(word))) { - if (++which > state) { - char *res = strdup(ast_get_context_name(c)); - ast_unlock_contexts(); - return res; - } - } - c = ast_walk_contexts(c); - } - - ast_unlock_contexts(); - return NULL; - } - - if (pos == 5) return state == 0 ? strdup("replace") : NULL; - - return NULL; -} - -/*! - * IGNOREPAT CLI stuff - */ -static int handle_context_add_ignorepat(int fd, int argc, char *argv[]) -{ - if (argc != 5) return RESULT_SHOWUSAGE; - if (strcmp(argv[3], "into")) return RESULT_SHOWUSAGE; - - if (ast_context_add_ignorepat(argv[4], argv[2], registrar)) { - switch (errno) { - case ENOMEM: - ast_cli(fd, "Out of free memory\n"); break; - - case ENOENT: - ast_cli(fd, "There is no existence of '%s' context\n", argv[4]); - break; - - case EEXIST: - ast_cli(fd, "Ignore pattern '%s' already included in '%s' context\n", - argv[2], argv[4]); - break; - - case EBUSY: - ast_cli(fd, "Failed to lock context(s) list, please, try again later\n"); - break; - - default: - ast_cli(fd, "Failed to add ingore pattern '%s' into '%s' context\n", - argv[2], argv[4]); - break; - } - return RESULT_FAILURE; - } - - ast_cli(fd, "Ignore pattern '%s' added into '%s' context\n", - argv[2], argv[4]); - return RESULT_SUCCESS; -} - -static char *complete_context_add_ignorepat(char *line, char *word, - int pos, int state) -{ - if (pos == 3) return state == 0 ? strdup("into") : NULL; - - if (pos == 4) { - struct ast_context *c; - int which = 0; - char *dupline, *duplinet, *ignorepat = NULL; - - dupline = strdup(line); - duplinet = dupline; - - if (duplinet) { - strsep(&duplinet, " "); /* skip 'add' */ - strsep(&duplinet, " "); /* skip 'ignorepat' */ - ignorepat = strsep(&duplinet, " "); - } - - if (ast_lock_contexts()) { - ast_log(LOG_ERROR, "Failed to lock contexts list\n"); - return NULL; - } - - c = ast_walk_contexts(NULL); - while (c) { - if (!strncmp(ast_get_context_name(c), word, strlen(word))) { - int serve_context = 1; - if (ignorepat) { - if (!ast_lock_context(c)) { - struct ast_ignorepat *ip; - ip = ast_walk_context_ignorepats(c, NULL); - while (ip && serve_context) { - if (!strcmp(ast_get_ignorepat_name(ip), ignorepat)) - serve_context = 0; - ip = ast_walk_context_ignorepats(c, ip); - } - ast_unlock_context(c); - } - } - if (serve_context) { - if (++which > state) { - char *context = strdup(ast_get_context_name(c)); - if (dupline) free(dupline); - ast_unlock_contexts(); - return context; - } - } - } - c = ast_walk_contexts(c); - } - - if (dupline) free(dupline); - ast_unlock_contexts(); - return NULL; - } - - return NULL; -} - -static int handle_context_remove_ignorepat(int fd, int argc, char *argv[]) -{ - if (argc != 5) return RESULT_SHOWUSAGE; - if (strcmp(argv[3], "from")) return RESULT_SHOWUSAGE; - - if (ast_context_remove_ignorepat(argv[4], argv[2], registrar)) { - switch (errno) { - case EBUSY: - ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); - break; - - case ENOENT: - ast_cli(fd, "There is no existence of '%s' context\n", argv[4]); - break; - - case EINVAL: - ast_cli(fd, "There is no existence of '%s' ignore pattern in '%s' context\n", - argv[2], argv[4]); - break; - - default: - ast_cli(fd, "Failed to remove ignore pattern '%s' from '%s' context\n", argv[2], argv[4]); - break; - } - return RESULT_FAILURE; - } - - ast_cli(fd, "Ignore pattern '%s' removed from '%s' context\n", - argv[2], argv[4]); - return RESULT_SUCCESS; -} - -static int pbx_load_module(void); - -static int handle_reload_extensions(int fd, int argc, char *argv[]) -{ - if (argc!=2) return RESULT_SHOWUSAGE; - pbx_load_module(); - return RESULT_SUCCESS; -} - -static char *complete_context_remove_ignorepat(char *line, char *word, - int pos, int state) -{ - struct ast_context *c; - int which = 0; - - if (pos == 2) { - if (ast_lock_contexts()) { - ast_log(LOG_WARNING, "Failed to lock contexts list\n"); - return NULL; - } - - c = ast_walk_contexts(NULL); - while (c) { - if (!ast_lock_context(c)) { - struct ast_ignorepat *ip; - - ip = ast_walk_context_ignorepats(c, NULL); - while (ip) { - if (!strncmp(ast_get_ignorepat_name(ip), word, strlen(word))) { - if (which + 1 > state) { - struct ast_context *cw; - int already_served = 0; - cw = ast_walk_contexts(NULL); - while (cw && cw != c && !already_served) { - if (!ast_lock_context(cw)) { - struct ast_ignorepat *ipw; - ipw = ast_walk_context_ignorepats(cw, NULL); - while (ipw) { - if (!strcmp(ast_get_ignorepat_name(ipw), - ast_get_ignorepat_name(ip))) already_served = 1; - ipw = ast_walk_context_ignorepats(cw, ipw); - } - ast_unlock_context(cw); - } - cw = ast_walk_contexts(cw); - } - if (!already_served) { - char *ret = strdup(ast_get_ignorepat_name(ip)); - ast_unlock_context(c); - ast_unlock_contexts(); - return ret; - } - } else - which++; - } - ip = ast_walk_context_ignorepats(c, ip); - } - - ast_unlock_context(c); - } - c = ast_walk_contexts(c); - } - - ast_unlock_contexts(); - return NULL; - } - - if (pos == 3) return state == 0 ? strdup("from") : NULL; - - if (pos == 4) { - char *dupline, *duplinet, *ignorepat; - - dupline = strdup(line); - if (!dupline) { - ast_log(LOG_WARNING, "Out of free memory\n"); - return NULL; - } - - duplinet = dupline; - strsep(&duplinet, " "); - strsep(&duplinet, " "); - ignorepat = strsep(&duplinet, " "); - - if (!ignorepat) { - free(dupline); - return NULL; - } - - if (ast_lock_contexts()) { - ast_log(LOG_WARNING, "Failed to lock contexts list\n"); - free(dupline); - return NULL; - } - - c = ast_walk_contexts(NULL); - while (c) { - if (!ast_lock_context(c)) { - struct ast_ignorepat *ip; - ip = ast_walk_context_ignorepats(c, NULL); - while (ip) { - if (!strcmp(ast_get_ignorepat_name(ip), ignorepat)) { - if (!strncmp(ast_get_context_name(c), word, strlen(word))) { - if (++which > state) { - char *ret = strdup(ast_get_context_name(c)); - free(dupline); - ast_unlock_context(c); - ast_unlock_contexts(); - return ret; - } - } - } - ip = ast_walk_context_ignorepats(c, ip); - } - - ast_unlock_context(c); - } - c = ast_walk_contexts(c); - } - - free(dupline); - ast_unlock_contexts(); - return NULL; - } - - return NULL; -} - -/*! - * CLI entries for commands provided by this module - */ -static struct ast_cli_entry context_dont_include_cli = - { { "dont", "include", NULL }, handle_context_dont_include, - "Remove a specified include from context", context_dont_include_help, - complete_context_dont_include }; - -static struct ast_cli_entry context_remove_extension_cli = - { { "remove", "extension", NULL }, handle_context_remove_extension, - "Remove a specified extension", context_remove_extension_help, - complete_context_remove_extension }; - -static struct ast_cli_entry context_add_include_cli = - { { "include", "context", NULL }, handle_context_add_include, - "Include context in other context", context_add_include_help, - complete_context_add_include }; - -static struct ast_cli_entry save_dialplan_cli = - { { "save", "dialplan", NULL }, handle_save_dialplan, - "Save dialplan", save_dialplan_help }; - -static struct ast_cli_entry context_add_extension_cli = - { { "add", "extension", NULL }, handle_context_add_extension, - "Add new extension into context", context_add_extension_help, - complete_context_add_extension }; - -static struct ast_cli_entry context_add_ignorepat_cli = - { { "add", "ignorepat", NULL }, handle_context_add_ignorepat, - "Add new ignore pattern", context_add_ignorepat_help, - complete_context_add_ignorepat }; - -static struct ast_cli_entry context_remove_ignorepat_cli = - { { "remove", "ignorepat", NULL }, handle_context_remove_ignorepat, - "Remove ignore pattern from context", context_remove_ignorepat_help, - complete_context_remove_ignorepat }; - -static struct ast_cli_entry reload_extensions_cli = - { { "extensions", "reload", NULL}, handle_reload_extensions, - "Reload extensions and *only* extensions", reload_extensions_help }; - -/*! - * Standard module functions ... - */ -int unload_module(void) -{ - ast_cli_unregister(&context_add_extension_cli); - if (static_config && !write_protect_config) - ast_cli_unregister(&save_dialplan_cli); - ast_cli_unregister(&context_add_include_cli); - ast_cli_unregister(&context_dont_include_cli); - ast_cli_unregister(&context_remove_extension_cli); - ast_cli_unregister(&context_remove_ignorepat_cli); - ast_cli_unregister(&context_add_ignorepat_cli); - ast_cli_unregister(&reload_extensions_cli); - ast_context_destroy(NULL, registrar); - return 0; -} - -static int pbx_load_module(void) -{ - struct ast_config *cfg; - struct ast_variable *v; - char *cxt, *ext, *pri, *appl, *data, *tc, *cidmatch; - struct ast_context *con; - char *end; - char *label; - char realvalue[256]; - int lastpri = -2; - - cfg = ast_config_load(config); - if (cfg) { - /* Use existing config to populate the PBX table */ - static_config = ast_true(ast_variable_retrieve(cfg, "general", - "static")); - write_protect_config = ast_true(ast_variable_retrieve(cfg, "general", - "writeprotect")); - autofallthrough_config = ast_true(ast_variable_retrieve(cfg, "general", - "autofallthrough")); - clearglobalvars_config = ast_true(ast_variable_retrieve(cfg, "general", - "clearglobalvars")); - option_priority_jumping = !ast_false(ast_variable_retrieve(cfg, "general", - "priorityjumping")); - - v = ast_variable_browse(cfg, "globals"); - while(v) { - memset(realvalue, 0, sizeof(realvalue)); - pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1); - pbx_builtin_setvar_helper(NULL, v->name, realvalue); - v = v->next; - } - cxt = ast_category_browse(cfg, NULL); - while(cxt) { - /* All categories but "general" or "globals" are considered contexts */ - if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals")) { - cxt = ast_category_browse(cfg, cxt); - continue; - } - if ((con=ast_context_create(&local_contexts,cxt, registrar))) { - v = ast_variable_browse(cfg, cxt); - while(v) { - if (!strcasecmp(v->name, "exten")) { - char *stringp=NULL; - int ipri = -2; - char realext[256]=""; - char *plus, *firstp, *firstc; - tc = strdup(v->value); - if(tc!=NULL){ - stringp=tc; - ext = strsep(&stringp, ","); - if (!ext) - ext=""; - pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext) - 1); - cidmatch = strchr(realext, '/'); - if (cidmatch) { - *cidmatch = '\0'; - cidmatch++; - ast_shrink_phone_number(cidmatch); - } - pri = strsep(&stringp, ","); - if (!pri) - pri=""; - label = strchr(pri, '('); - if (label) { - *label = '\0'; - label++; - end = strchr(label, ')'); - if (end) - *end = '\0'; - else - ast_log(LOG_WARNING, "Label missing trailing ')' at line %d\n", v->lineno); - } - plus = strchr(pri, '+'); - if (plus) { - *plus = '\0'; - plus++; - } - if (!strcmp(pri,"hint")) - ipri=PRIORITY_HINT; - else if (!strcmp(pri, "next") || !strcmp(pri, "n")) { - if (lastpri > -2) - ipri = lastpri + 1; - else - ast_log(LOG_WARNING, "Can't use 'next' priority on the first entry!\n"); - } else if (!strcmp(pri, "same") || !strcmp(pri, "s")) { - if (lastpri > -2) - ipri = lastpri; - else - ast_log(LOG_WARNING, "Can't use 'same' priority on the first entry!\n"); - } else { - if (sscanf(pri, "%d", &ipri) != 1) { - if ((ipri = ast_findlabel_extension2(NULL, con, realext, pri, cidmatch)) < 1) { - ast_log(LOG_WARNING, "Invalid priority/label '%s' at line %d\n", pri, v->lineno); - ipri = 0; - } - } - } - appl = stringp; - if (!appl) - appl=""; - /* Find the first occurrence of either '(' or ',' */ - firstc = strchr(appl, ','); - firstp = strchr(appl, '('); - if (firstc && ((!firstp) || (firstc < firstp))) { - /* comma found, no parenthesis */ - /* or both found, but comma found first */ - appl = strsep(&stringp, ","); - data = stringp; - } else if ((!firstc) && (!firstp)) { - /* Neither found */ - data = ""; - } else { - /* Final remaining case is parenthesis found first */ - appl = strsep(&stringp, "("); - data = stringp; - end = strrchr(data, ')'); - if ((end = strrchr(data, ')'))) { - *end = '\0'; - } else { - ast_log(LOG_WARNING, "No closing parenthesis found? '%s(%s'\n", appl, data); - } - ast_process_quotes_and_slashes(data, ',', '|'); - } - - if (!data) - data=""; - while(*appl && (*appl < 33)) appl++; - if (ipri) { - if (plus) - ipri += atoi(plus); - lastpri = ipri; - if(!option_dontwarn) { - if (!strcmp(realext, "_.")) - ast_log(LOG_WARNING, "The use of '_.' for an extension is strongly discouraged and can have unexpected behavior. Please use '_X.' instead at line %d\n", v->lineno); - } - if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), FREE, registrar)) { - ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno); - } - } - free(tc); - } else fprintf(stderr,"Error strdup returned NULL in %s\n",__PRETTY_FUNCTION__); - } else if(!strcasecmp(v->name, "include")) { - memset(realvalue, 0, sizeof(realvalue)); - pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1); - if (ast_context_add_include2(con, realvalue, registrar)) - ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt); - } else if(!strcasecmp(v->name, "ignorepat")) { - memset(realvalue, 0, sizeof(realvalue)); - pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1); - if (ast_context_add_ignorepat2(con, realvalue, registrar)) - ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt); - } else if (!strcasecmp(v->name, "switch") || !strcasecmp(v->name, "lswitch") || !strcasecmp(v->name, "eswitch")) { - char *stringp=NULL; - memset(realvalue, 0, sizeof(realvalue)); - if (!strcasecmp(v->name, "switch")) - pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1); - else - strncpy(realvalue, v->value, sizeof(realvalue) - 1); - tc = realvalue; - stringp=tc; - appl = strsep(&stringp, "/"); - data = strsep(&stringp, ""); - if (!data) - data = ""; - if (ast_context_add_switch2(con, appl, data, !strcasecmp(v->name, "eswitch"), registrar)) - ast_log(LOG_WARNING, "Unable to include switch '%s' in context '%s'\n", v->value, cxt); - } - v = v->next; - } - } - cxt = ast_category_browse(cfg, cxt); - } - ast_config_destroy(cfg); - } - ast_merge_contexts_and_delete(&local_contexts,registrar); - - for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con)) - ast_context_verify_includes(con); - - pbx_set_autofallthrough(autofallthrough_config); - - return 0; -} - -int load_module(void) -{ - if (pbx_load_module()) return -1; - - ast_cli_register(&context_remove_extension_cli); - ast_cli_register(&context_dont_include_cli); - ast_cli_register(&context_add_include_cli); - if (static_config && !write_protect_config) - ast_cli_register(&save_dialplan_cli); - ast_cli_register(&context_add_extension_cli); - ast_cli_register(&context_add_ignorepat_cli); - ast_cli_register(&context_remove_ignorepat_cli); - ast_cli_register(&reload_extensions_cli); - - return 0; -} - -int reload(void) -{ - ast_context_destroy(NULL, registrar); - if (clearglobalvars_config) - pbx_builtin_clear_globals(); - pbx_load_module(); - return 0; -} - -int usecount(void) -{ - return 0; -} - -char *description(void) -{ - return dtext; -} - -char *key(void) -{ - return ASTERISK_GPL_KEY; -} diff --git a/1.2-netsec/pbx/pbx_dundi.c b/1.2-netsec/pbx/pbx_dundi.c deleted file mode 100644 index 8f0457296..000000000 --- a/1.2-netsec/pbx/pbx_dundi.c +++ /dev/null @@ -1,4831 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief Distributed Universal Number Discovery (DUNDi) - * - */ - -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <sys/socket.h> -#include <string.h> -#include <errno.h> -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(SOLARIS) || defined(__Darwin__) -#include <sys/types.h> -#include <netinet/in_systm.h> -#endif -#include <netinet/ip.h> -#include <sys/ioctl.h> -#include <netinet/in.h> -#include <net/if.h> -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__Darwin__) -#include <net/if_dl.h> -#include <ifaddrs.h> -#endif -#include <zlib.h> - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/file.h" -#include "asterisk/logger.h" -#include "asterisk/channel.h" -#include "asterisk/config.h" -#include "asterisk/options.h" -#include "asterisk/pbx.h" -#include "asterisk/module.h" -#include "asterisk/frame.h" -#include "asterisk/file.h" -#include "asterisk/cli.h" -#include "asterisk/lock.h" -#include "asterisk/md5.h" -#include "asterisk/dundi.h" -#include "asterisk/sched.h" -#include "asterisk/io.h" -#include "asterisk/utils.h" -#include "asterisk/crypto.h" -#include "asterisk/astdb.h" -#include "asterisk/acl.h" -#include "asterisk/aes.h" - -#include "dundi-parser.h" - -#define MAX_RESULTS 64 - -#define MAX_PACKET_SIZE 8192 - -extern char ast_config_AST_KEY_DIR[]; - -static char *tdesc = "Distributed Universal Number Discovery (DUNDi)"; - -static char *app = "DUNDiLookup"; -static char *synopsis = "Look up a number with DUNDi"; -static char *descrip = -"DUNDiLookup(number[|context[|options]])\n" -" Looks up a given number in the global context specified or in\n" -"the reserved 'e164' context if not specified. Returns -1 if the channel\n" -"is hungup during the lookup or 0 otherwise. On completion, the variable\n" -"${DUNDTECH} and ${DUNDDEST} will contain the technology and destination\n" -"of the appropriate technology and destination to access the number. If no\n" -"answer was found, and the priority n + 101 exists, execution will continue\n" -"at that location. Note that this will only occur if the global priority\n" -"jumping option is enabled in extensions.conf. If the 'b' option is specified,\n" -"the internal DUNDi cache will by bypassed.\n"; - -#define DUNDI_MODEL_INBOUND (1 << 0) -#define DUNDI_MODEL_OUTBOUND (1 << 1) -#define DUNDI_MODEL_SYMMETRIC (DUNDI_MODEL_INBOUND | DUNDI_MODEL_OUTBOUND) - -/* Keep times of last 10 lookups */ -#define DUNDI_TIMING_HISTORY 10 - -#define FLAG_ISREG (1 << 0) /* Transaction is register request */ -#define FLAG_DEAD (1 << 1) /* Transaction is dead */ -#define FLAG_FINAL (1 << 2) /* Transaction has final message sent */ -#define FLAG_ISQUAL (1 << 3) /* Transaction is a qualification */ -#define FLAG_ENCRYPT (1 << 4) /* Transaction is encrypted wiht ECX/DCX */ -#define FLAG_SENDFULLKEY (1 << 5) /* Send full key on transaction */ -#define FLAG_STOREHIST (1 << 6) /* Record historic performance */ - -#define DUNDI_FLAG_INTERNAL_NOPARTIAL (1 << 17) - -#if 0 -#define DUNDI_SECRET_TIME 15 /* Testing only */ -#else -#define DUNDI_SECRET_TIME DUNDI_DEFAULT_CACHE_TIME -#endif - -#define KEY_OUT 0 -#define KEY_IN 1 - -static struct io_context *io; -static struct sched_context *sched; -static int netsocket = -1; -static pthread_t netthreadid = AST_PTHREADT_NULL; -static pthread_t precachethreadid = AST_PTHREADT_NULL; -static int tos = 0; -static int dundidebug = 0; -static int authdebug = 0; -static int dundi_ttl = DUNDI_DEFAULT_TTL; -static int dundi_key_ttl = DUNDI_DEFAULT_KEY_EXPIRE; -static int dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME; -static int global_autokilltimeout = 0; -static dundi_eid global_eid; -static int default_expiration = 60; -static int global_storehistory = 0; -static char dept[80]; -static char org[80]; -static char locality[80]; -static char stateprov[80]; -static char country[80]; -static char email[80]; -static char phone[80]; -static char secretpath[80]; -static char cursecret[80]; -static char ipaddr[80]; -static time_t rotatetime; -static dundi_eid empty_eid = { { 0, 0, 0, 0, 0, 0 } }; -struct permission { - struct permission *next; - int allow; - char name[0]; -}; - -struct dundi_packet { - struct dundi_hdr *h; - struct dundi_packet *next; - int datalen; - struct dundi_transaction *parent; - int retransid; - int retrans; - unsigned char data[0]; -}; - -struct dundi_hint_metadata { - unsigned short flags; - char exten[AST_MAX_EXTENSION]; -}; - -struct dundi_precache_queue { - struct dundi_precache_queue *next; - char *context; - time_t expiration; - char number[0]; -}; - -struct dundi_request; - -struct dundi_transaction { - struct sockaddr_in addr; /* Other end of transaction */ - struct timeval start; /* When this transaction was created */ - dundi_eid eids[DUNDI_MAX_STACK + 1]; - int eidcount; /* Number of eids in eids */ - dundi_eid us_eid; /* Our EID, to them */ - dundi_eid them_eid; /* Their EID, to us */ - aes_encrypt_ctx ecx; /* AES 128 Encryption context */ - aes_decrypt_ctx dcx; /* AES 128 Decryption context */ - unsigned int flags; /* Has final packet been sent */ - int ttl; /* Remaining TTL for queries on this one */ - int thread; /* We have a calling thread */ - int retranstimer; /* How long to wait before retransmissions */ - int autokillid; /* ID to kill connection if answer doesn't come back fast enough */ - int autokilltimeout; /* Recommended timeout for autokill */ - unsigned short strans; /* Our transaction identifier */ - unsigned short dtrans; /* Their transaction identifer */ - unsigned char iseqno; /* Next expected received seqno */ - unsigned char oiseqno; /* Last received incoming seqno */ - unsigned char oseqno; /* Next transmitted seqno */ - unsigned char aseqno; /* Last acknowledge seqno */ - struct dundi_packet *packets; /* Packets to be retransmitted */ - struct dundi_packet *lasttrans; /* Last transmitted / ACK'd packet */ - struct dundi_transaction *next; /* Next with respect to the parent */ - struct dundi_request *parent; /* Parent request (if there is one) */ - struct dundi_transaction *allnext; /* Next with respect to all DUNDi transactions */ -} *alltrans; - -struct dundi_request { - char dcontext[AST_MAX_EXTENSION]; - char number[AST_MAX_EXTENSION]; - dundi_eid query_eid; - dundi_eid root_eid; - struct dundi_result *dr; - struct dundi_entity_info *dei; - struct dundi_hint_metadata *hmd; - int maxcount; - int respcount; - int expiration; - int cbypass; - int pfds[2]; - unsigned long crc32; /* CRC-32 of all but root EID's in avoid list */ - struct dundi_transaction *trans; /* Transactions */ - struct dundi_request *next; -} *requests; - -static struct dundi_mapping { - char dcontext[AST_MAX_EXTENSION]; - char lcontext[AST_MAX_EXTENSION]; - int weight; - int options; - int tech; - int dead; - char dest[AST_MAX_EXTENSION]; - struct dundi_mapping *next; -} *mappings = NULL; - -static struct dundi_peer { - dundi_eid eid; - struct sockaddr_in addr; /* Address of DUNDi peer */ - struct permission *permit; - struct permission *include; - struct permission *precachesend; - struct permission *precachereceive; - dundi_eid us_eid; - char inkey[80]; - char outkey[80]; - int dead; - int registerid; - int qualifyid; - int sentfullkey; - int order; - unsigned char txenckey[256]; /* Transmitted encrypted key + sig */ - unsigned char rxenckey[256]; /* Cache received encrypted key + sig */ - unsigned long us_keycrc32; /* CRC-32 of our key */ - aes_encrypt_ctx us_ecx; /* Cached AES 128 Encryption context */ - aes_decrypt_ctx us_dcx; /* Cached AES 128 Decryption context */ - unsigned long them_keycrc32;/* CRC-32 of our key */ - aes_encrypt_ctx them_ecx; /* Cached AES 128 Encryption context */ - aes_decrypt_ctx them_dcx; /* Cached AES 128 Decryption context */ - time_t keyexpire; /* When to expire/recreate key */ - int registerexpire; - int lookuptimes[DUNDI_TIMING_HISTORY]; - char *lookups[DUNDI_TIMING_HISTORY]; - int avgms; - struct dundi_transaction *regtrans; /* Registration transaction */ - struct dundi_transaction *qualtrans; /* Qualify transaction */ - struct dundi_transaction *keypending; - int model; /* Pull model */ - int pcmodel; /* Push/precache model */ - int dynamic; /* Are we dynamic? */ - int lastms; /* Last measured latency */ - int maxms; /* Max permissible latency */ - struct timeval qualtx; /* Time of transmit */ - struct dundi_peer *next; -} *peers; - -static struct dundi_precache_queue *pcq; - -AST_MUTEX_DEFINE_STATIC(peerlock); -AST_MUTEX_DEFINE_STATIC(pclock); - -static int dundi_xmit(struct dundi_packet *pack); - -static void dundi_debug_output(const char *data) -{ - if (dundidebug) - ast_verbose("%s", data); -} - -static void dundi_error_output(const char *data) -{ - ast_log(LOG_WARNING, "%s", data); -} - -static int has_permission(struct permission *ps, char *cont) -{ - int res=0; - while(ps) { - if (!strcasecmp(ps->name, "all") || !strcasecmp(ps->name, cont)) - res = ps->allow; - ps = ps->next; - } - return res; -} - -static char *tech2str(int tech) -{ - switch(tech) { - case DUNDI_PROTO_NONE: - return "None"; - case DUNDI_PROTO_IAX: - return "IAX2"; - case DUNDI_PROTO_SIP: - return "SIP"; - case DUNDI_PROTO_H323: - return "H323"; - default: - return "Unknown"; - } -} - -static int str2tech(char *str) -{ - if (!strcasecmp(str, "IAX") || !strcasecmp(str, "IAX2")) - return DUNDI_PROTO_IAX; - else if (!strcasecmp(str, "SIP")) - return DUNDI_PROTO_SIP; - else if (!strcasecmp(str, "H323")) - return DUNDI_PROTO_H323; - else - return -1; -} - -static int dundi_lookup_internal(struct dundi_result *result, int maxret, struct ast_channel *chan, const char *dcontext, const char *number, int ttl, int blockempty, struct dundi_hint_metadata *md, int *expiration, int cybpass, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int direct[]); -static int dundi_precache_internal(const char *context, const char *number, int ttl, dundi_eid *avoids[]); -static struct dundi_transaction *create_transaction(struct dundi_peer *p); -static struct dundi_transaction *find_transaction(struct dundi_hdr *hdr, struct sockaddr_in *sin) -{ - /* Look for an exact match first */ - struct dundi_transaction *trans; - trans = alltrans; - while(trans) { - if (!inaddrcmp(&trans->addr, sin) && - ((trans->strans == (ntohs(hdr->dtrans) & 32767)) /* Matches our destination */ || - ((trans->dtrans == (ntohs(hdr->strans) & 32767)) && (!hdr->dtrans))) /* We match their destination */) { - if (hdr->strans) - trans->dtrans = ntohs(hdr->strans) & 32767; - break; - } - trans = trans->allnext; - } - if (!trans) { - switch(hdr->cmdresp & 0x7f) { - case DUNDI_COMMAND_DPDISCOVER: - case DUNDI_COMMAND_EIDQUERY: - case DUNDI_COMMAND_PRECACHERQ: - case DUNDI_COMMAND_REGREQ: - case DUNDI_COMMAND_NULL: - case DUNDI_COMMAND_ENCRYPT: - if (hdr->strans) { - /* Create new transaction */ - trans = create_transaction(NULL); - if (trans) { - memcpy(&trans->addr, sin, sizeof(trans->addr)); - trans->dtrans = ntohs(hdr->strans) & 32767; - } else - ast_log(LOG_WARNING, "Out of memory!\n"); - } - break; - default: - break; - } - } - return trans; -} - -static int dundi_send(struct dundi_transaction *trans, int cmdresp, int flags, int final, struct dundi_ie_data *ied); - -static int dundi_ack(struct dundi_transaction *trans, int final) -{ - return dundi_send(trans, DUNDI_COMMAND_ACK, 0, final, NULL); -} -static void dundi_reject(struct dundi_hdr *h, struct sockaddr_in *sin) -{ - struct { - struct dundi_packet pack; - struct dundi_hdr hdr; - } tmp; - struct dundi_transaction trans; - /* Never respond to an INVALID with another INVALID */ - if (h->cmdresp == DUNDI_COMMAND_INVALID) - return; - memset(&tmp, 0, sizeof(tmp)); - memset(&trans, 0, sizeof(trans)); - memcpy(&trans.addr, sin, sizeof(trans.addr)); - tmp.hdr.strans = h->dtrans; - tmp.hdr.dtrans = h->strans; - tmp.hdr.iseqno = h->oseqno; - tmp.hdr.oseqno = h->iseqno; - tmp.hdr.cmdresp = DUNDI_COMMAND_INVALID; - tmp.hdr.cmdflags = 0; - tmp.pack.h = (struct dundi_hdr *)tmp.pack.data; - tmp.pack.datalen = sizeof(struct dundi_hdr); - tmp.pack.parent = &trans; - dundi_xmit(&tmp.pack); -} - -static void reset_global_eid(void) -{ -#if defined(SIOCGIFHWADDR) - int x,s; - char eid_str[20]; - struct ifreq ifr; - - s = socket(AF_INET, SOCK_STREAM, 0); - if (s > 0) { - x = 0; - for(x=0;x<10;x++) { - memset(&ifr, 0, sizeof(ifr)); - snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth%d", x); - if (!ioctl(s, SIOCGIFHWADDR, &ifr)) { - memcpy(&global_eid, ((unsigned char *)&ifr.ifr_hwaddr) + 2, sizeof(global_eid)); - ast_log(LOG_DEBUG, "Seeding global EID '%s' from '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid), ifr.ifr_name); - close(s); - return; - } - } - close(s); - } -#else -#if defined(ifa_broadaddr) && !defined(SOLARIS) - char eid_str[20]; - struct ifaddrs *ifap; - - if (getifaddrs(&ifap) == 0) { - struct ifaddrs *p; - for (p = ifap; p; p = p->ifa_next) { - if (p->ifa_addr->sa_family == AF_LINK) { - struct sockaddr_dl* sdp = (struct sockaddr_dl*) p->ifa_addr; - memcpy( - &(global_eid.eid), - sdp->sdl_data + sdp->sdl_nlen, 6); - ast_log(LOG_DEBUG, "Seeding global EID '%s' from '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid), ifap->ifa_name); - freeifaddrs(ifap); - return; - } - } - freeifaddrs(ifap); - } -#endif -#endif - ast_log(LOG_NOTICE, "No ethernet interface found for seeding global EID You will have to set it manually.\n"); -} - -static int get_trans_id(void) -{ - struct dundi_transaction *t; - int stid = (rand() % 32766) + 1; - int tid = stid; - do { - t = alltrans; - while(t) { - if (t->strans == tid) - break; - t = t->allnext; - } - if (!t) - return tid; - tid = (tid % 32766) + 1; - } while (tid != stid); - return 0; -} - -static int reset_transaction(struct dundi_transaction *trans) -{ - int tid; - tid = get_trans_id(); - if (tid < 1) - return -1; - trans->strans = tid; - trans->dtrans = 0; - trans->iseqno = 0; - trans->oiseqno = 0; - trans->oseqno = 0; - trans->aseqno = 0; - ast_clear_flag(trans, FLAG_FINAL); - return 0; -} - -static struct dundi_peer *find_peer(dundi_eid *eid) -{ - struct dundi_peer *cur; - if (!eid) - eid = &empty_eid; - cur = peers; - while(cur) { - if (!dundi_eid_cmp(&cur->eid,eid)) - return cur; - cur = cur->next; - } - return NULL; -} - -static void build_iv(unsigned char *iv) -{ - /* XXX Would be nice to be more random XXX */ - unsigned int *fluffy; - int x; - fluffy = (unsigned int *)(iv); - for (x=0;x<4;x++) - fluffy[x] = rand(); -} - -struct dundi_query_state { - dundi_eid *eids[DUNDI_MAX_STACK + 1]; - int directs[DUNDI_MAX_STACK + 1]; - dundi_eid reqeid; - char called_context[AST_MAX_EXTENSION]; - char called_number[AST_MAX_EXTENSION]; - struct dundi_mapping *maps; - int nummaps; - int nocache; - struct dundi_transaction *trans; - void *chal; - int challen; - int ttl; - char fluffy[0]; -}; - -static int dundi_lookup_local(struct dundi_result *dr, struct dundi_mapping *map, char *called_number, dundi_eid *us_eid, int anscnt, struct dundi_hint_metadata *hmd) -{ - struct ast_flags flags = {0}; - int x; - if (!ast_strlen_zero(map->lcontext)) { - if (ast_exists_extension(NULL, map->lcontext, called_number, 1, NULL)) - ast_set_flag(&flags, DUNDI_FLAG_EXISTS); - if (ast_canmatch_extension(NULL, map->lcontext, called_number, 1, NULL)) - ast_set_flag(&flags, DUNDI_FLAG_CANMATCH); - if (ast_matchmore_extension(NULL, map->lcontext, called_number, 1, NULL)) - ast_set_flag(&flags, DUNDI_FLAG_MATCHMORE); - if (ast_ignore_pattern(map->lcontext, called_number)) - ast_set_flag(&flags, DUNDI_FLAG_IGNOREPAT); - - /* Clearly we can't say 'don't ask' anymore if we found anything... */ - if (ast_test_flag(&flags, AST_FLAGS_ALL)) - ast_clear_flag_nonstd(hmd, DUNDI_HINT_DONT_ASK); - - if (map->options & DUNDI_FLAG_INTERNAL_NOPARTIAL) { - /* Skip partial answers */ - ast_clear_flag(&flags, DUNDI_FLAG_MATCHMORE|DUNDI_FLAG_CANMATCH); - } - if (ast_test_flag(&flags, AST_FLAGS_ALL)) { - struct varshead headp; - struct ast_var_t *newvariable; - ast_set_flag(&flags, map->options & 0xffff); - ast_copy_flags(dr + anscnt, &flags, AST_FLAGS_ALL); - dr[anscnt].techint = map->tech; - dr[anscnt].weight = map->weight; - dr[anscnt].expiration = dundi_cache_time; - ast_copy_string(dr[anscnt].tech, tech2str(map->tech), sizeof(dr[anscnt].tech)); - dr[anscnt].eid = *us_eid; - dundi_eid_to_str(dr[anscnt].eid_str, sizeof(dr[anscnt].eid_str), &dr[anscnt].eid); - if (ast_test_flag(&flags, DUNDI_FLAG_EXISTS)) { - AST_LIST_HEAD_INIT_NOLOCK(&headp); - newvariable = ast_var_assign("NUMBER", called_number); - AST_LIST_INSERT_HEAD(&headp, newvariable, entries); - newvariable = ast_var_assign("EID", dr[anscnt].eid_str); - AST_LIST_INSERT_HEAD(&headp, newvariable, entries); - newvariable = ast_var_assign("SECRET", cursecret); - AST_LIST_INSERT_HEAD(&headp, newvariable, entries); - newvariable = ast_var_assign("IPADDR", ipaddr); - AST_LIST_INSERT_HEAD(&headp, newvariable, entries); - pbx_substitute_variables_varshead(&headp, map->dest, dr[anscnt].dest, sizeof(dr[anscnt].dest)); - while (!AST_LIST_EMPTY(&headp)) { /* List Deletion. */ - newvariable = AST_LIST_REMOVE_HEAD(&headp, entries); - ast_var_delete(newvariable); - } - } else - dr[anscnt].dest[0] = '\0'; - anscnt++; - } else { - /* No answers... Find the fewest number of digits from the - number for which we have no answer. */ - char tmp[AST_MAX_EXTENSION]; - for (x=0;x<AST_MAX_EXTENSION;x++) { - tmp[x] = called_number[x]; - if (!tmp[x]) - break; - if (!ast_canmatch_extension(NULL, map->lcontext, tmp, 1, NULL)) { - /* Oops found something we can't match. If this is longer - than the running hint, we have to consider it */ - if (strlen(tmp) > strlen(hmd->exten)) { - ast_copy_string(hmd->exten, tmp, sizeof(hmd->exten)); - } - break; - } - } - } - } - return anscnt; -} - -static void destroy_trans(struct dundi_transaction *trans, int fromtimeout); - -static void *dundi_lookup_thread(void *data) -{ - struct dundi_query_state *st = data; - struct dundi_result dr[MAX_RESULTS]; - struct dundi_ie_data ied; - struct dundi_hint_metadata hmd; - char eid_str[20]; - int res, x; - int ouranswers=0; - int max = 999999; - int expiration = dundi_cache_time; - - ast_log(LOG_DEBUG, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context, - st->eids[0] ? dundi_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) : "ourselves"); - memset(&ied, 0, sizeof(ied)); - memset(&dr, 0, sizeof(dr)); - memset(&hmd, 0, sizeof(hmd)); - /* Assume 'don't ask for anything' and 'unaffected', no TTL expired */ - hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED; - for (x=0;x<st->nummaps;x++) - ouranswers = dundi_lookup_local(dr, st->maps + x, st->called_number, &st->trans->us_eid, ouranswers, &hmd); - if (ouranswers < 0) - ouranswers = 0; - for (x=0;x<ouranswers;x++) { - if (dr[x].weight < max) - max = dr[x].weight; - } - - if (max) { - /* If we do not have a canonical result, keep looking */ - res = dundi_lookup_internal(dr + ouranswers, MAX_RESULTS - ouranswers, NULL, st->called_context, st->called_number, st->ttl, 1, &hmd, &expiration, st->nocache, 0, NULL, st->eids, st->directs); - if (res > 0) { - /* Append answer in result */ - ouranswers += res; - } else { - if ((res < -1) && (!ouranswers)) - dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_DUPLICATE, "Duplicate Request Pending"); - } - } - ast_mutex_lock(&peerlock); - /* Truncate if "don't ask" isn't present */ - if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK)) - hmd.exten[0] = '\0'; - if (ast_test_flag(st->trans, FLAG_DEAD)) { - ast_log(LOG_DEBUG, "Our transaction went away!\n"); - st->trans->thread = 0; - destroy_trans(st->trans, 0); - } else { - for (x=0;x<ouranswers;x++) { - /* Add answers */ - if (dr[x].expiration && (expiration > dr[x].expiration)) - expiration = dr[x].expiration; - dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest); - } - dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten); - dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration); - dundi_send(st->trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied); - st->trans->thread = 0; - } - ast_mutex_unlock(&peerlock); - free(st); - return NULL; -} - -static void *dundi_precache_thread(void *data) -{ - struct dundi_query_state *st = data; - struct dundi_ie_data ied; - struct dundi_hint_metadata hmd; - char eid_str[20]; - - ast_log(LOG_DEBUG, "Whee, precaching '%s@%s' for '%s'\n", st->called_number, st->called_context, - st->eids[0] ? dundi_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) : "ourselves"); - memset(&ied, 0, sizeof(ied)); - - /* Now produce precache */ - dundi_precache_internal(st->called_context, st->called_number, st->ttl, st->eids); - - ast_mutex_lock(&peerlock); - /* Truncate if "don't ask" isn't present */ - if (!ast_test_flag_nonstd(&hmd, DUNDI_HINT_DONT_ASK)) - hmd.exten[0] = '\0'; - if (ast_test_flag(st->trans, FLAG_DEAD)) { - ast_log(LOG_DEBUG, "Our transaction went away!\n"); - st->trans->thread = 0; - destroy_trans(st->trans, 0); - } else { - dundi_send(st->trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied); - st->trans->thread = 0; - } - ast_mutex_unlock(&peerlock); - free(st); - return NULL; -} - -static int dundi_query_eid_internal(struct dundi_entity_info *dei, const char *dcontext, dundi_eid *eid, struct dundi_hint_metadata *hmd, int ttl, int blockempty, dundi_eid *avoid[]); - -static void *dundi_query_thread(void *data) -{ - struct dundi_query_state *st = data; - struct dundi_entity_info dei; - struct dundi_ie_data ied; - struct dundi_hint_metadata hmd; - char eid_str[20]; - int res; - ast_log(LOG_DEBUG, "Whee, looking up '%s@%s' for '%s'\n", st->called_number, st->called_context, - st->eids[0] ? dundi_eid_to_str(eid_str, sizeof(eid_str), st->eids[0]) : "ourselves"); - memset(&ied, 0, sizeof(ied)); - memset(&dei, 0, sizeof(dei)); - memset(&hmd, 0, sizeof(hmd)); - if (!dundi_eid_cmp(&st->trans->us_eid, &st->reqeid)) { - /* Ooh, it's us! */ - ast_log(LOG_DEBUG, "Neat, someone look for us!\n"); - ast_copy_string(dei.orgunit, dept, sizeof(dei.orgunit)); - ast_copy_string(dei.org, org, sizeof(dei.org)); - ast_copy_string(dei.locality, locality, sizeof(dei.locality)); - ast_copy_string(dei.stateprov, stateprov, sizeof(dei.stateprov)); - ast_copy_string(dei.country, country, sizeof(dei.country)); - ast_copy_string(dei.email, email, sizeof(dei.email)); - ast_copy_string(dei.phone, phone, sizeof(dei.phone)); - res = 1; - } else { - /* If we do not have a canonical result, keep looking */ - res = dundi_query_eid_internal(&dei, st->called_context, &st->reqeid, &hmd, st->ttl, 1, st->eids); - } - ast_mutex_lock(&peerlock); - if (ast_test_flag(st->trans, FLAG_DEAD)) { - ast_log(LOG_DEBUG, "Our transaction went away!\n"); - st->trans->thread = 0; - destroy_trans(st->trans, 0); - } else { - if (res) { - dundi_ie_append_str(&ied, DUNDI_IE_DEPARTMENT, dei.orgunit); - dundi_ie_append_str(&ied, DUNDI_IE_ORGANIZATION, dei.org); - dundi_ie_append_str(&ied, DUNDI_IE_LOCALITY, dei.locality); - dundi_ie_append_str(&ied, DUNDI_IE_STATE_PROV, dei.stateprov); - dundi_ie_append_str(&ied, DUNDI_IE_COUNTRY, dei.country); - dundi_ie_append_str(&ied, DUNDI_IE_EMAIL, dei.email); - dundi_ie_append_str(&ied, DUNDI_IE_PHONE, dei.phone); - if (!ast_strlen_zero(dei.ipaddr)) - dundi_ie_append_str(&ied, DUNDI_IE_IPADDR, dei.ipaddr); - } - dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten); - dundi_send(st->trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied); - st->trans->thread = 0; - } - ast_mutex_unlock(&peerlock); - free(st); - return NULL; -} - -static int dundi_answer_entity(struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext) -{ - struct dundi_query_state *st; - int totallen; - int x; - int skipfirst=0; - struct dundi_ie_data ied; - char eid_str[20]; - char *s; - pthread_t lookupthread; - pthread_attr_t attr; - if (ies->eidcount > 1) { - /* Since it is a requirement that the first EID is the authenticating host - and the last EID is the root, it is permissible that the first and last EID - could be the same. In that case, we should go ahead copy only the "root" section - since we will not need it for authentication. */ - if (!dundi_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1])) - skipfirst = 1; - } - totallen = sizeof(struct dundi_query_state); - totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid); - st = malloc(totallen); - if (st) { - memset(st, 0, totallen); - ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context)); - memcpy(&st->reqeid, ies->reqeid, sizeof(st->reqeid)); - st->trans = trans; - st->ttl = ies->ttl - 1; - if (st->ttl < 0) - st->ttl = 0; - s = st->fluffy; - for (x=skipfirst;ies->eids[x];x++) { - st->eids[x-skipfirst] = (dundi_eid *)s; - *st->eids[x-skipfirst] = *ies->eids[x]; - s += sizeof(dundi_eid); - } - ast_log(LOG_DEBUG, "Answering EID query for '%s@%s'!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), ies->reqeid), ies->called_context); - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - trans->thread = 1; - if (ast_pthread_create(&lookupthread, &attr, dundi_query_thread, st)) { - trans->thread = 0; - ast_log(LOG_WARNING, "Unable to create thread!\n"); - free(st); - memset(&ied, 0, sizeof(ied)); - dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads"); - dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied); - return -1; - } - } else { - ast_log(LOG_WARNING, "Out of memory!\n"); - memset(&ied, 0, sizeof(ied)); - dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory"); - dundi_send(trans, DUNDI_COMMAND_EIDRESPONSE, 0, 1, &ied); - return -1; - } - return 0; -} - -static int cache_save_hint(dundi_eid *eidpeer, struct dundi_request *req, struct dundi_hint *hint, int expiration) -{ - int unaffected; - char key1[256]; - char key2[256]; - char eidpeer_str[20]; - char eidroot_str[20]; - char data[80]; - time_t timeout; - - if (expiration < 0) - expiration = dundi_cache_time; - - /* Only cache hint if "don't ask" is there... */ - if (!ast_test_flag_nonstd(hint, htons(DUNDI_HINT_DONT_ASK))) - return 0; - - unaffected = ast_test_flag_nonstd(hint, htons(DUNDI_HINT_UNAFFECTED)); - - dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer); - dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid); - snprintf(key1, sizeof(key1), "hint/%s/%s/%s/e%08lx", eidpeer_str, hint->data, req->dcontext, unaffected ? 0 : req->crc32); - snprintf(key2, sizeof(key2), "hint/%s/%s/%s/r%s", eidpeer_str, hint->data, req->dcontext, eidroot_str); - - time(&timeout); - timeout += expiration; - snprintf(data, sizeof(data), "%ld|", (long)(timeout)); - - ast_db_put("dundi/cache", key1, data); - ast_log(LOG_DEBUG, "Caching hint at '%s'\n", key1); - ast_db_put("dundi/cache", key2, data); - ast_log(LOG_DEBUG, "Caching hint at '%s'\n", key2); - return 0; -} - -static int cache_save(dundi_eid *eidpeer, struct dundi_request *req, int start, int unaffected, int expiration, int push) -{ - int x; - char key1[256]; - char key2[256]; - char data[1024]; - char eidpeer_str[20]; - char eidroot_str[20]; - time_t timeout; - - if (expiration < 1) - expiration = dundi_cache_time; - - /* Keep pushes a little longer, cut pulls a little short */ - if (push) - expiration += 10; - else - expiration -= 10; - if (expiration < 1) - expiration = 1; - dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), eidpeer); - dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid); - snprintf(key1, sizeof(key1), "%s/%s/%s/e%08lx", eidpeer_str, req->number, req->dcontext, unaffected ? 0 : req->crc32); - snprintf(key2, sizeof(key2), "%s/%s/%s/r%s", eidpeer_str, req->number, req->dcontext, eidroot_str); - /* Build request string */ - time(&timeout); - timeout += expiration; - snprintf(data, sizeof(data), "%ld|", (long)(timeout)); - for (x=start;x<req->respcount;x++) { - /* Skip anything with an illegal pipe in it */ - if (strchr(req->dr[x].dest, '|')) - continue; - snprintf(data + strlen(data), sizeof(data) - strlen(data), "%d/%d/%d/%s/%s|", - req->dr[x].flags, req->dr[x].weight, req->dr[x].techint, req->dr[x].dest, - dundi_eid_to_str_short(eidpeer_str, sizeof(eidpeer_str), &req->dr[x].eid)); - } - ast_db_put("dundi/cache", key1, data); - ast_db_put("dundi/cache", key2, data); - return 0; -} - -static int dundi_prop_precache(struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext) -{ - struct dundi_query_state *st; - int totallen; - int x,z; - struct dundi_ie_data ied; - char *s; - struct dundi_result dr2[MAX_RESULTS]; - struct dundi_request dr; - struct dundi_hint_metadata hmd; - - struct dundi_mapping *cur; - int mapcount; - int skipfirst = 0; - - pthread_t lookupthread; - pthread_attr_t attr; - - memset(&dr2, 0, sizeof(dr2)); - memset(&dr, 0, sizeof(dr)); - memset(&hmd, 0, sizeof(hmd)); - - /* Forge request structure to hold answers for cache */ - hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED; - dr.dr = dr2; - dr.maxcount = MAX_RESULTS; - dr.expiration = dundi_cache_time; - dr.hmd = &hmd; - dr.pfds[0] = dr.pfds[1] = -1; - trans->parent = &dr; - ast_copy_string(dr.dcontext, ies->called_context ? ies->called_context : "e164", sizeof(dr.dcontext)); - ast_copy_string(dr.number, ies->called_number, sizeof(dr.number)); - - for (x=0;x<ies->anscount;x++) { - if (trans->parent->respcount < trans->parent->maxcount) { - /* Make sure it's not already there */ - for (z=0;z<trans->parent->respcount;z++) { - if ((trans->parent->dr[z].techint == ies->answers[x]->protocol) && - !strcmp(trans->parent->dr[z].dest, (char *)ies->answers[x]->data)) - break; - } - if (z == trans->parent->respcount) { - /* Copy into parent responses */ - trans->parent->dr[trans->parent->respcount].flags = ntohs(ies->answers[x]->flags); - trans->parent->dr[trans->parent->respcount].techint = ies->answers[x]->protocol; - trans->parent->dr[trans->parent->respcount].weight = ntohs(ies->answers[x]->weight); - trans->parent->dr[trans->parent->respcount].eid = ies->answers[x]->eid; - if (ies->expiration > 0) - trans->parent->dr[trans->parent->respcount].expiration = ies->expiration; - else - trans->parent->dr[trans->parent->respcount].expiration = dundi_cache_time; - dundi_eid_to_str(trans->parent->dr[trans->parent->respcount].eid_str, - sizeof(trans->parent->dr[trans->parent->respcount].eid_str), - &ies->answers[x]->eid); - ast_copy_string(trans->parent->dr[trans->parent->respcount].dest, (char *)ies->answers[x]->data, - sizeof(trans->parent->dr[trans->parent->respcount].dest)); - ast_copy_string(trans->parent->dr[trans->parent->respcount].tech, tech2str(ies->answers[x]->protocol), - sizeof(trans->parent->dr[trans->parent->respcount].tech)); - trans->parent->respcount++; - ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK); - } else if (trans->parent->dr[z].weight > ies->answers[x]->weight) { - /* Update weight if appropriate */ - trans->parent->dr[z].weight = ies->answers[x]->weight; - } - } else - ast_log(LOG_NOTICE, "Dropping excessive answers in precache for %s@%s\n", - trans->parent->number, trans->parent->dcontext); - - } - /* Save all the results (if any) we had. Even if no results, still cache lookup. */ - cache_save(&trans->them_eid, trans->parent, 0, 0, ies->expiration, 1); - if (ies->hint) - cache_save_hint(&trans->them_eid, trans->parent, ies->hint, ies->expiration); - - totallen = sizeof(struct dundi_query_state); - /* Count matching map entries */ - mapcount = 0; - cur = mappings; - while(cur) { - if (!strcasecmp(cur->dcontext, ccontext)) - mapcount++; - cur = cur->next; - } - - /* If no maps, return -1 immediately */ - if (!mapcount) - return -1; - - if (ies->eidcount > 1) { - /* Since it is a requirement that the first EID is the authenticating host - and the last EID is the root, it is permissible that the first and last EID - could be the same. In that case, we should go ahead copy only the "root" section - since we will not need it for authentication. */ - if (!dundi_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1])) - skipfirst = 1; - } - - /* Prepare to run a query and then propagate that as necessary */ - totallen += mapcount * sizeof(struct dundi_mapping); - totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid); - st = malloc(totallen); - if (st) { - memset(st, 0, totallen); - ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context)); - ast_copy_string(st->called_number, ies->called_number, sizeof(st->called_number)); - st->trans = trans; - st->ttl = ies->ttl - 1; - st->nocache = ies->cbypass; - if (st->ttl < 0) - st->ttl = 0; - s = st->fluffy; - for (x=skipfirst;ies->eids[x];x++) { - st->eids[x-skipfirst] = (dundi_eid *)s; - *st->eids[x-skipfirst] = *ies->eids[x]; - st->directs[x-skipfirst] = ies->eid_direct[x]; - s += sizeof(dundi_eid); - } - /* Append mappings */ - x = 0; - st->maps = (struct dundi_mapping *)s; - cur = mappings; - while(cur) { - if (!strcasecmp(cur->dcontext, ccontext)) { - if (x < mapcount) { - st->maps[x] = *cur; - st->maps[x].next = NULL; - x++; - } - } - cur = cur->next; - } - st->nummaps = mapcount; - ast_log(LOG_DEBUG, "Forwarding precache for '%s@%s'!\n", ies->called_number, ies->called_context); - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - trans->thread = 1; - if (ast_pthread_create(&lookupthread, &attr, dundi_precache_thread, st)) { - trans->thread = 0; - ast_log(LOG_WARNING, "Unable to create thread!\n"); - free(st); - memset(&ied, 0, sizeof(ied)); - dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads"); - dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied); - return -1; - } - } else { - ast_log(LOG_WARNING, "Out of memory!\n"); - memset(&ied, 0, sizeof(ied)); - dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory"); - dundi_send(trans, DUNDI_COMMAND_PRECACHERP, 0, 1, &ied); - return -1; - } - return 0; -} - -static int dundi_answer_query(struct dundi_transaction *trans, struct dundi_ies *ies, char *ccontext) -{ - struct dundi_query_state *st; - int totallen; - int x; - struct dundi_ie_data ied; - char *s; - struct dundi_mapping *cur; - int mapcount; - int skipfirst = 0; - - pthread_t lookupthread; - pthread_attr_t attr; - totallen = sizeof(struct dundi_query_state); - /* Count matching map entries */ - mapcount = 0; - cur = mappings; - while(cur) { - if (!strcasecmp(cur->dcontext, ccontext)) - mapcount++; - cur = cur->next; - } - /* If no maps, return -1 immediately */ - if (!mapcount) - return -1; - - if (ies->eidcount > 1) { - /* Since it is a requirement that the first EID is the authenticating host - and the last EID is the root, it is permissible that the first and last EID - could be the same. In that case, we should go ahead copy only the "root" section - since we will not need it for authentication. */ - if (!dundi_eid_cmp(ies->eids[0], ies->eids[ies->eidcount - 1])) - skipfirst = 1; - } - - totallen += mapcount * sizeof(struct dundi_mapping); - totallen += (ies->eidcount - skipfirst) * sizeof(dundi_eid); - st = malloc(totallen); - if (st) { - memset(st, 0, totallen); - ast_copy_string(st->called_context, ies->called_context, sizeof(st->called_context)); - ast_copy_string(st->called_number, ies->called_number, sizeof(st->called_number)); - st->trans = trans; - st->ttl = ies->ttl - 1; - st->nocache = ies->cbypass; - if (st->ttl < 0) - st->ttl = 0; - s = st->fluffy; - for (x=skipfirst;ies->eids[x];x++) { - st->eids[x-skipfirst] = (dundi_eid *)s; - *st->eids[x-skipfirst] = *ies->eids[x]; - st->directs[x-skipfirst] = ies->eid_direct[x]; - s += sizeof(dundi_eid); - } - /* Append mappings */ - x = 0; - st->maps = (struct dundi_mapping *)s; - cur = mappings; - while(cur) { - if (!strcasecmp(cur->dcontext, ccontext)) { - if (x < mapcount) { - st->maps[x] = *cur; - st->maps[x].next = NULL; - x++; - } - } - cur = cur->next; - } - st->nummaps = mapcount; - ast_log(LOG_DEBUG, "Answering query for '%s@%s'!\n", ies->called_number, ies->called_context); - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - trans->thread = 1; - if (ast_pthread_create(&lookupthread, &attr, dundi_lookup_thread, st)) { - trans->thread = 0; - ast_log(LOG_WARNING, "Unable to create thread!\n"); - free(st); - memset(&ied, 0, sizeof(ied)); - dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of threads"); - dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied); - return -1; - } - } else { - ast_log(LOG_WARNING, "Out of memory!\n"); - memset(&ied, 0, sizeof(ied)); - dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Out of memory"); - dundi_send(trans, DUNDI_COMMAND_DPRESPONSE, 0, 1, &ied); - return -1; - } - return 0; -} - -static int cache_lookup_internal(time_t now, struct dundi_request *req, char *key, char *eid_str_full, int *lowexpiration) -{ - char data[1024]; - char *ptr, *term, *src; - int tech; - struct ast_flags flags; - int weight; - int length; - int z; - int expiration; - char fs[256]; - time_t timeout; - /* Build request string */ - if (!ast_db_get("dundi/cache", key, data, sizeof(data))) { - ptr = data; - if (sscanf(ptr, "%d|%n", (int *)&timeout, &length) == 1) { - expiration = timeout - now; - if (expiration > 0) { - ast_log(LOG_DEBUG, "Found cache expiring in %d seconds!\n", (int)(timeout - now)); - ptr += length; - while((sscanf(ptr, "%d/%d/%d/%n", &(flags.flags), &weight, &tech, &length) == 3)) { - ptr += length; - term = strchr(ptr, '|'); - if (term) { - *term = '\0'; - src = strrchr(ptr, '/'); - if (src) { - *src = '\0'; - src++; - } else - src = ""; - ast_log(LOG_DEBUG, "Found cached answer '%s/%s' originally from '%s' with flags '%s' on behalf of '%s'\n", - tech2str(tech), ptr, src, dundi_flags2str(fs, sizeof(fs), flags.flags), eid_str_full); - /* Make sure it's not already there */ - for (z=0;z<req->respcount;z++) { - if ((req->dr[z].techint == tech) && - !strcmp(req->dr[z].dest, ptr)) - break; - } - if (z == req->respcount) { - /* Copy into parent responses */ - ast_copy_flags(&(req->dr[req->respcount]), &flags, AST_FLAGS_ALL); - req->dr[req->respcount].weight = weight; - req->dr[req->respcount].techint = tech; - req->dr[req->respcount].expiration = expiration; - dundi_str_short_to_eid(&req->dr[req->respcount].eid, src); - dundi_eid_to_str(req->dr[req->respcount].eid_str, - sizeof(req->dr[req->respcount].eid_str), &req->dr[req->respcount].eid); - ast_copy_string(req->dr[req->respcount].dest, ptr, - sizeof(req->dr[req->respcount].dest)); - ast_copy_string(req->dr[req->respcount].tech, tech2str(tech), - sizeof(req->dr[req->respcount].tech)); - req->respcount++; - ast_clear_flag_nonstd(req->hmd, DUNDI_HINT_DONT_ASK); - } else if (req->dr[z].weight > weight) - req->dr[z].weight = weight; - ptr = term + 1; - } - } - /* We found *something* cached */ - if (expiration < *lowexpiration) - *lowexpiration = expiration; - return 1; - } else - ast_db_del("dundi/cache", key); - } else - ast_db_del("dundi/cache", key); - } - - return 0; -} - -static int cache_lookup(struct dundi_request *req, dundi_eid *peer_eid, unsigned long crc32, int *lowexpiration) -{ - char key[256]; - char eid_str[20]; - char eidroot_str[20]; - time_t now; - int res=0; - int res2=0; - char eid_str_full[20]; - char tmp[256]=""; - int x; - - time(&now); - dundi_eid_to_str_short(eid_str, sizeof(eid_str), peer_eid); - dundi_eid_to_str_short(eidroot_str, sizeof(eidroot_str), &req->root_eid); - dundi_eid_to_str(eid_str_full, sizeof(eid_str_full), peer_eid); - snprintf(key, sizeof(key), "%s/%s/%s/e%08lx", eid_str, req->number, req->dcontext, crc32); - res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration); - snprintf(key, sizeof(key), "%s/%s/%s/e%08lx", eid_str, req->number, req->dcontext, 0L); - res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration); - snprintf(key, sizeof(key), "%s/%s/%s/r%s", eid_str, req->number, req->dcontext, eidroot_str); - res |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration); - x = 0; - if (!req->respcount) { - while(!res2) { - /* Look and see if we have a hint that would preclude us from looking at this - peer for this number. */ - if (!(tmp[x] = req->number[x])) - break; - x++; - /* Check for hints */ - snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08lx", eid_str, tmp, req->dcontext, crc32); - res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration); - snprintf(key, sizeof(key), "hint/%s/%s/%s/e%08lx", eid_str, tmp, req->dcontext, 0L); - res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration); - snprintf(key, sizeof(key), "hint/%s/%s/%s/r%s", eid_str, tmp, req->dcontext, eidroot_str); - res2 |= cache_lookup_internal(now, req, key, eid_str_full, lowexpiration); - if (res2) { - if (strlen(tmp) > strlen(req->hmd->exten)) { - /* Update meta data if appropriate */ - ast_copy_string(req->hmd->exten, tmp, sizeof(req->hmd->exten)); - } - } - } - res |= res2; - } - - return res; -} - -static void qualify_peer(struct dundi_peer *peer, int schedonly); - -static void apply_peer(struct dundi_transaction *trans, struct dundi_peer *p) -{ - if (!trans->addr.sin_addr.s_addr) - memcpy(&trans->addr, &p->addr, sizeof(trans->addr)); - trans->us_eid = p->us_eid; - trans->them_eid = p->eid; - /* Enable encryption if appropriate */ - if (!ast_strlen_zero(p->inkey)) - ast_set_flag(trans, FLAG_ENCRYPT); - if (p->maxms) { - trans->autokilltimeout = p->maxms; - trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER; - if (p->lastms > 1) { - trans->retranstimer = p->lastms * 2; - /* Keep it from being silly */ - if (trans->retranstimer < 150) - trans->retranstimer = 150; - } - if (trans->retranstimer > DUNDI_DEFAULT_RETRANS_TIMER) - trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER; - } else - trans->autokilltimeout = global_autokilltimeout; -} - -static int do_register_expire(void *data) -{ - struct dundi_peer *peer = data; - char eid_str[20]; - /* Called with peerlock already held */ - ast_log(LOG_DEBUG, "Register expired for '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); - peer->registerexpire = -1; - peer->lastms = 0; - memset(&peer->addr, 0, sizeof(peer->addr)); - return 0; -} - -static int update_key(struct dundi_peer *peer) -{ - unsigned char key[16]; - struct ast_key *ekey, *skey; - char eid_str[20]; - int res; - if (!peer->keyexpire || (peer->keyexpire < time(NULL))) { - build_iv(key); - aes_encrypt_key128(key, &peer->us_ecx); - aes_decrypt_key128(key, &peer->us_dcx); - ekey = ast_key_get(peer->inkey, AST_KEY_PUBLIC); - if (!ekey) { - ast_log(LOG_NOTICE, "No such key '%s' for creating RSA encrypted shared key for '%s'!\n", - peer->inkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); - return -1; - } - skey = ast_key_get(peer->outkey, AST_KEY_PRIVATE); - if (!skey) { - ast_log(LOG_NOTICE, "No such key '%s' for signing RSA encrypted shared key for '%s'!\n", - peer->outkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); - return -1; - } - if ((res = ast_encrypt_bin(peer->txenckey, key, sizeof(key), ekey)) != 128) { - ast_log(LOG_NOTICE, "Whoa, got a weird encrypt size (%d != %d)!\n", res, 128); - return -1; - } - if ((res = ast_sign_bin(skey, (char *)peer->txenckey, 128, peer->txenckey + 128))) { - ast_log(LOG_NOTICE, "Failed to sign key (%d)!\n", res); - return -1; - } - peer->us_keycrc32 = crc32(0L, peer->txenckey, 128); - peer->sentfullkey = 0; - /* Looks good */ - time(&peer->keyexpire); - peer->keyexpire += dundi_key_ttl; - } - return 0; -} - -static int encrypt_memcpy(unsigned char *dst, unsigned char *src, int len, unsigned char *iv, aes_encrypt_ctx *ecx) -{ - unsigned char curblock[16]; - int x; - memcpy(curblock, iv, sizeof(curblock)); - while(len > 0) { - for (x=0;x<16;x++) - curblock[x] ^= src[x]; - aes_encrypt(curblock, dst, ecx); - memcpy(curblock, dst, sizeof(curblock)); - dst += 16; - src += 16; - len -= 16; - } - return 0; -} -static int decrypt_memcpy(unsigned char *dst, unsigned char *src, int len, unsigned char *iv, aes_decrypt_ctx *dcx) -{ - unsigned char lastblock[16]; - int x; - memcpy(lastblock, iv, sizeof(lastblock)); - while(len > 0) { - aes_decrypt(src, dst, dcx); - for (x=0;x<16;x++) - dst[x] ^= lastblock[x]; - memcpy(lastblock, src, sizeof(lastblock)); - dst += 16; - src += 16; - len -= 16; - } - return 0; -} - -static struct dundi_hdr *dundi_decrypt(struct dundi_transaction *trans, unsigned char *dst, int *dstlen, struct dundi_hdr *ohdr, struct dundi_encblock *src, int srclen) -{ - int space = *dstlen; - unsigned long bytes; - struct dundi_hdr *h; - unsigned char *decrypt_space; - decrypt_space = alloca(srclen); - if (!decrypt_space) - return NULL; - decrypt_memcpy(decrypt_space, src->encdata, srclen, src->iv, &trans->dcx); - /* Setup header */ - h = (struct dundi_hdr *)dst; - *h = *ohdr; - bytes = space - 6; - if (uncompress(dst + 6, &bytes, decrypt_space, srclen) != Z_OK) { - ast_log(LOG_DEBUG, "Ouch, uncompress failed :(\n"); - return NULL; - } - /* Update length */ - *dstlen = bytes + 6; - /* Return new header */ - return h; -} - -static int dundi_encrypt(struct dundi_transaction *trans, struct dundi_packet *pack) -{ - unsigned char *compress_space; - int len; - int res; - unsigned long bytes; - struct dundi_ie_data ied; - struct dundi_peer *peer; - unsigned char iv[16]; - len = pack->datalen + pack->datalen / 100 + 42; - compress_space = alloca(len); - if (compress_space) { - memset(compress_space, 0, len); - /* We care about everthing save the first 6 bytes of header */ - bytes = len; - res = compress(compress_space, &bytes, pack->data + 6, pack->datalen - 6); - if (res != Z_OK) { - ast_log(LOG_DEBUG, "Ouch, compression failed!\n"); - return -1; - } - memset(&ied, 0, sizeof(ied)); - /* Say who we are */ - if (!pack->h->iseqno && !pack->h->oseqno) { - /* Need the key in the first copy */ - if (!(peer = find_peer(&trans->them_eid))) - return -1; - if (update_key(peer)) - return -1; - if (!peer->sentfullkey) - ast_set_flag(trans, FLAG_SENDFULLKEY); - /* Append key data */ - dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid); - if (ast_test_flag(trans, FLAG_SENDFULLKEY)) { - dundi_ie_append_raw(&ied, DUNDI_IE_SHAREDKEY, peer->txenckey, 128); - dundi_ie_append_raw(&ied, DUNDI_IE_SIGNATURE, peer->txenckey + 128, 128); - } else { - dundi_ie_append_int(&ied, DUNDI_IE_KEYCRC32, peer->us_keycrc32); - } - /* Setup contexts */ - trans->ecx = peer->us_ecx; - trans->dcx = peer->us_dcx; - - /* We've sent the full key */ - peer->sentfullkey = 1; - } - /* Build initialization vector */ - build_iv(iv); - /* Add the field, rounded up to 16 bytes */ - dundi_ie_append_encdata(&ied, DUNDI_IE_ENCDATA, iv, NULL, ((bytes + 15) / 16) * 16); - /* Copy the data */ - if ((ied.pos + bytes) >= sizeof(ied.buf)) { - ast_log(LOG_NOTICE, "Final packet too large!\n"); - return -1; - } - encrypt_memcpy(ied.buf + ied.pos, compress_space, bytes, iv, &trans->ecx); - ied.pos += ((bytes + 15) / 16) * 16; - /* Reconstruct header */ - pack->datalen = sizeof(struct dundi_hdr); - pack->h->cmdresp = DUNDI_COMMAND_ENCRYPT; - pack->h->cmdflags = 0; - memcpy(pack->h->ies, ied.buf, ied.pos); - pack->datalen += ied.pos; - return 0; - } - return -1; -} - -static int check_key(struct dundi_peer *peer, unsigned char *newkey, unsigned char *newsig, unsigned long keycrc32) -{ - unsigned char dst[128]; - int res; - struct ast_key *key, *skey; - char eid_str[20]; - if (option_debug) - ast_log(LOG_DEBUG, "Expected '%08lx' got '%08lx'\n", peer->them_keycrc32, keycrc32); - if (peer->them_keycrc32 && (peer->them_keycrc32 == keycrc32)) { - /* A match */ - return 1; - } else if (!newkey || !newsig) - return 0; - if (!memcmp(peer->rxenckey, newkey, 128) && - !memcmp(peer->rxenckey + 128, newsig, 128)) { - /* By definition, a match */ - return 1; - } - /* Decrypt key */ - key = ast_key_get(peer->outkey, AST_KEY_PRIVATE); - if (!key) { - ast_log(LOG_NOTICE, "Unable to find key '%s' to decode shared key from '%s'\n", - peer->outkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); - return -1; - } - - skey = ast_key_get(peer->inkey, AST_KEY_PUBLIC); - if (!skey) { - ast_log(LOG_NOTICE, "Unable to find key '%s' to verify shared key from '%s'\n", - peer->inkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); - return -1; - } - - /* First check signature */ - res = ast_check_signature_bin(skey, (char *)newkey, 128, newsig); - if (res) - return 0; - - res = ast_decrypt_bin(dst, newkey, sizeof(dst), key); - if (res != 16) { - if (res >= 0) - ast_log(LOG_NOTICE, "Weird, key decoded to the wrong size (%d)\n", res); - return 0; - } - /* Decrypted, passes signature */ - ast_log(LOG_DEBUG, "Wow, new key combo passed signature and decrypt!\n"); - memcpy(peer->rxenckey, newkey, 128); - memcpy(peer->rxenckey + 128, newsig, 128); - peer->them_keycrc32 = crc32(0L, peer->rxenckey, 128); - aes_decrypt_key128(dst, &peer->them_dcx); - aes_encrypt_key128(dst, &peer->them_ecx); - return 1; -} - -static int handle_command_response(struct dundi_transaction *trans, struct dundi_hdr *hdr, int datalen, int encrypted) -{ - /* Handle canonical command / response */ - int final = hdr->cmdresp & 0x80; - int cmd = hdr->cmdresp & 0x7f; - int x,y,z; - int resp; - int res; - int authpass=0; - unsigned char *bufcpy; - struct dundi_ie_data ied; - struct dundi_ies ies; - struct dundi_peer *peer; - char eid_str[20]; - char eid_str2[20]; - memset(&ied, 0, sizeof(ied)); - memset(&ies, 0, sizeof(ies)); - if (datalen) { - bufcpy = alloca(datalen); - if (!bufcpy) - return -1; - /* Make a copy for parsing */ - memcpy(bufcpy, hdr->ies, datalen); - ast_log(LOG_DEBUG, "Got canonical message %d (%d), %d bytes data%s\n", cmd, hdr->oseqno, datalen, final ? " (Final)" : ""); - if (dundi_parse_ies(&ies, bufcpy, datalen) < 0) { - ast_log(LOG_WARNING, "Failed to parse DUNDI information elements!\n"); - return -1; - } - } - switch(cmd) { - case DUNDI_COMMAND_DPDISCOVER: - case DUNDI_COMMAND_EIDQUERY: - case DUNDI_COMMAND_PRECACHERQ: - if (cmd == DUNDI_COMMAND_EIDQUERY) - resp = DUNDI_COMMAND_EIDRESPONSE; - else if (cmd == DUNDI_COMMAND_PRECACHERQ) - resp = DUNDI_COMMAND_PRECACHERP; - else - resp = DUNDI_COMMAND_DPRESPONSE; - /* A dialplan or entity discover -- qualify by highest level entity */ - peer = find_peer(ies.eids[0]); - if (!peer) { - dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, NULL); - dundi_send(trans, resp, 0, 1, &ied); - } else { - int hasauth = 0; - trans->us_eid = peer->us_eid; - if (strlen(peer->inkey)) { - hasauth = encrypted; - } else - hasauth = 1; - if (hasauth) { - /* Okay we're authentiated and all, now we check if they're authorized */ - if (!ies.called_context) - ies.called_context = "e164"; - if (cmd == DUNDI_COMMAND_EIDQUERY) { - res = dundi_answer_entity(trans, &ies, ies.called_context); - } else { - if (ast_strlen_zero(ies.called_number)) { - /* They're not permitted to access that context */ - dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_GENERAL, "Invalid or missing number/entity"); - dundi_send(trans, resp, 0, 1, &ied); - } else if ((cmd == DUNDI_COMMAND_DPDISCOVER) && - (peer->model & DUNDI_MODEL_INBOUND) && - has_permission(peer->permit, ies.called_context)) { - res = dundi_answer_query(trans, &ies, ies.called_context); - if (res < 0) { - /* There is no such dundi context */ - dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unsupported DUNDI Context"); - dundi_send(trans, resp, 0, 1, &ied); - } - } else if ((cmd = DUNDI_COMMAND_PRECACHERQ) && - (peer->pcmodel & DUNDI_MODEL_INBOUND) && - has_permission(peer->include, ies.called_context)) { - res = dundi_prop_precache(trans, &ies, ies.called_context); - if (res < 0) { - /* There is no such dundi context */ - dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unsupported DUNDI Context"); - dundi_send(trans, resp, 0, 1, &ied); - } - } else { - /* They're not permitted to access that context */ - dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Permission to context denied"); - dundi_send(trans, resp, 0, 1, &ied); - } - } - } else { - /* They're not permitted to access that context */ - dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Unencrypted responses not permitted"); - dundi_send(trans, resp, 0, 1, &ied); - } - } - break; - case DUNDI_COMMAND_REGREQ: - /* A register request -- should only have one entity */ - peer = find_peer(ies.eids[0]); - if (!peer || !peer->dynamic) { - dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, NULL); - dundi_send(trans, DUNDI_COMMAND_REGRESPONSE, 0, 1, &ied); - } else { - int hasauth = 0; - trans->us_eid = peer->us_eid; - if (!ast_strlen_zero(peer->inkey)) { - hasauth = encrypted; - } else - hasauth = 1; - if (hasauth) { - int expire = default_expiration; - char iabuf[INET_ADDRSTRLEN]; - char data[256]; - int needqual = 0; - if (peer->registerexpire > -1) - ast_sched_del(sched, peer->registerexpire); - peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer); - ast_inet_ntoa(iabuf, sizeof(iabuf), trans->addr.sin_addr); - snprintf(data, sizeof(data), "%s:%d:%d", iabuf, ntohs(trans->addr.sin_port), expire); - ast_db_put("dundi/dpeers", dundi_eid_to_str_short(eid_str, sizeof(eid_str), &peer->eid), data); - if (inaddrcmp(&peer->addr, &trans->addr)) { - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Registered DUNDi peer '%s' at '%s:%d'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), iabuf, ntohs(trans->addr.sin_port)); - needqual = 1; - } - - memcpy(&peer->addr, &trans->addr, sizeof(peer->addr)); - dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration); - dundi_send(trans, DUNDI_COMMAND_REGRESPONSE, 0, 1, &ied); - if (needqual) - qualify_peer(peer, 1); - } - } - break; - case DUNDI_COMMAND_DPRESPONSE: - /* A dialplan response, lets see what we got... */ - if (ies.cause < 1) { - /* Success of some sort */ - ast_log(LOG_DEBUG, "Looks like success of some sort (%d), %d answers\n", ies.cause, ies.anscount); - if (ast_test_flag(trans, FLAG_ENCRYPT)) { - authpass = encrypted; - } else - authpass = 1; - if (authpass) { - /* Pass back up answers */ - if (trans->parent && trans->parent->dr) { - y = trans->parent->respcount; - for (x=0;x<ies.anscount;x++) { - if (trans->parent->respcount < trans->parent->maxcount) { - /* Make sure it's not already there */ - for (z=0;z<trans->parent->respcount;z++) { - if ((trans->parent->dr[z].techint == ies.answers[x]->protocol) && - !strcmp(trans->parent->dr[z].dest, (char *)ies.answers[x]->data)) - break; - } - if (z == trans->parent->respcount) { - /* Copy into parent responses */ - trans->parent->dr[trans->parent->respcount].flags = ntohs(ies.answers[x]->flags); - trans->parent->dr[trans->parent->respcount].techint = ies.answers[x]->protocol; - trans->parent->dr[trans->parent->respcount].weight = ntohs(ies.answers[x]->weight); - trans->parent->dr[trans->parent->respcount].eid = ies.answers[x]->eid; - if (ies.expiration > 0) - trans->parent->dr[trans->parent->respcount].expiration = ies.expiration; - else - trans->parent->dr[trans->parent->respcount].expiration = dundi_cache_time; - dundi_eid_to_str(trans->parent->dr[trans->parent->respcount].eid_str, - sizeof(trans->parent->dr[trans->parent->respcount].eid_str), - &ies.answers[x]->eid); - ast_copy_string(trans->parent->dr[trans->parent->respcount].dest, (char *)ies.answers[x]->data, - sizeof(trans->parent->dr[trans->parent->respcount].dest)); - ast_copy_string(trans->parent->dr[trans->parent->respcount].tech, tech2str(ies.answers[x]->protocol), - sizeof(trans->parent->dr[trans->parent->respcount].tech)); - trans->parent->respcount++; - ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK); - } else if (trans->parent->dr[z].weight > ies.answers[x]->weight) { - /* Update weight if appropriate */ - trans->parent->dr[z].weight = ies.answers[x]->weight; - } - } else - ast_log(LOG_NOTICE, "Dropping excessive answers to request for %s@%s\n", - trans->parent->number, trans->parent->dcontext); - } - /* Save all the results (if any) we had. Even if no results, still cache lookup. Let - the cache know if this request was unaffected by our entity list. */ - cache_save(&trans->them_eid, trans->parent, y, - ies.hint ? ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_UNAFFECTED)) : 0, ies.expiration, 0); - if (ies.hint) { - cache_save_hint(&trans->them_eid, trans->parent, ies.hint, ies.expiration); - if (ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_TTL_EXPIRED))) - ast_set_flag_nonstd(trans->parent->hmd, DUNDI_HINT_TTL_EXPIRED); - if (ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_DONT_ASK))) { - if (strlen((char *)ies.hint->data) > strlen(trans->parent->hmd->exten)) { - ast_copy_string(trans->parent->hmd->exten, (char *)ies.hint->data, - sizeof(trans->parent->hmd->exten)); - } - } else { - ast_clear_flag_nonstd(trans->parent->hmd, DUNDI_HINT_DONT_ASK); - } - } - if (ies.expiration > 0) { - if (trans->parent->expiration > ies.expiration) { - trans->parent->expiration = ies.expiration; - } - } - } - /* Close connection if not final */ - if (!final) - dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); - } - - } else { - /* Auth failure, check for data */ - if (!final) { - /* Cancel if they didn't already */ - dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); - } - } - break; - case DUNDI_COMMAND_EIDRESPONSE: - /* A dialplan response, lets see what we got... */ - if (ies.cause < 1) { - /* Success of some sort */ - ast_log(LOG_DEBUG, "Looks like success of some sort (%d)\n", ies.cause); - if (ast_test_flag(trans, FLAG_ENCRYPT)) { - authpass = encrypted; - } else - authpass = 1; - if (authpass) { - /* Pass back up answers */ - if (trans->parent && trans->parent->dei && ies.q_org) { - if (!trans->parent->respcount) { - trans->parent->respcount++; - if (ies.q_dept) - ast_copy_string(trans->parent->dei->orgunit, ies.q_dept, sizeof(trans->parent->dei->orgunit)); - if (ies.q_org) - ast_copy_string(trans->parent->dei->org, ies.q_org, sizeof(trans->parent->dei->org)); - if (ies.q_locality) - ast_copy_string(trans->parent->dei->locality, ies.q_locality, sizeof(trans->parent->dei->locality)); - if (ies.q_stateprov) - ast_copy_string(trans->parent->dei->stateprov, ies.q_stateprov, sizeof(trans->parent->dei->stateprov)); - if (ies.q_country) - ast_copy_string(trans->parent->dei->country, ies.q_country, sizeof(trans->parent->dei->country)); - if (ies.q_email) - ast_copy_string(trans->parent->dei->email, ies.q_email, sizeof(trans->parent->dei->email)); - if (ies.q_phone) - ast_copy_string(trans->parent->dei->phone, ies.q_phone, sizeof(trans->parent->dei->phone)); - if (ies.q_ipaddr) - ast_copy_string(trans->parent->dei->ipaddr, ies.q_ipaddr, sizeof(trans->parent->dei->ipaddr)); - if (!dundi_eid_cmp(&trans->them_eid, &trans->parent->query_eid)) { - /* If it's them, update our address */ - ast_inet_ntoa(trans->parent->dei->ipaddr, sizeof(trans->parent->dei->ipaddr), - trans->addr.sin_addr); - } - } - if (ies.hint) { - if (ast_test_flag_nonstd(ies.hint, htons(DUNDI_HINT_TTL_EXPIRED))) - ast_set_flag_nonstd(trans->parent->hmd, DUNDI_HINT_TTL_EXPIRED); - } - } - /* Close connection if not final */ - if (!final) - dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); - } - - } else { - /* Auth failure, check for data */ - if (!final) { - /* Cancel if they didn't already */ - dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); - } - } - break; - case DUNDI_COMMAND_REGRESPONSE: - /* A dialplan response, lets see what we got... */ - if (ies.cause < 1) { - int hasauth; - /* Success of some sort */ - if (ast_test_flag(trans, FLAG_ENCRYPT)) { - hasauth = encrypted; - } else - hasauth = 1; - - if (!hasauth) { - ast_log(LOG_NOTICE, "Reponse to register not authorized!\n"); - if (!final) { - dundi_ie_append_cause(&ied, DUNDI_IE_CAUSE, DUNDI_CAUSE_NOAUTH, "Improper signature in answer"); - dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, &ied); - } - } else { - ast_log(LOG_DEBUG, "Yay, we've registered as '%s' to '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &trans->us_eid), - dundi_eid_to_str(eid_str2, sizeof(eid_str2), &trans->them_eid)); - /* Close connection if not final */ - if (!final) - dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); - } - } else { - /* Auth failure, cancel if they didn't for some reason */ - if (!final) { - dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); - } - } - break; - case DUNDI_COMMAND_INVALID: - case DUNDI_COMMAND_NULL: - case DUNDI_COMMAND_PRECACHERP: - /* Do nothing special */ - if (!final) - dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); - break; - case DUNDI_COMMAND_ENCREJ: - if ((ast_test_flag(trans, FLAG_SENDFULLKEY)) || !trans->lasttrans || !(peer = find_peer(&trans->them_eid))) { - /* No really, it's over at this point */ - if (!final) - dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); - } else { - /* Send with full key */ - ast_set_flag(trans, FLAG_SENDFULLKEY); - if (final) { - /* Ooops, we got a final message, start by sending ACK... */ - dundi_ack(trans, hdr->cmdresp & 0x80); - trans->aseqno = trans->iseqno; - /* Now, we gotta create a new transaction */ - if (!reset_transaction(trans)) { - /* Make sure handle_frame doesn't destroy us */ - hdr->cmdresp &= 0x7f; - /* Parse the message we transmitted */ - memset(&ies, 0, sizeof(ies)); - dundi_parse_ies(&ies, trans->lasttrans->h->ies, trans->lasttrans->datalen - sizeof(struct dundi_hdr)); - /* Reconstruct outgoing encrypted packet */ - memset(&ied, 0, sizeof(ied)); - dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid); - dundi_ie_append_raw(&ied, DUNDI_IE_SHAREDKEY, peer->txenckey, 128); - dundi_ie_append_raw(&ied, DUNDI_IE_SIGNATURE, peer->txenckey + 128, 128); - if (ies.encblock) - dundi_ie_append_encdata(&ied, DUNDI_IE_ENCDATA, ies.encblock->iv, ies.encblock->encdata, ies.enclen); - dundi_send(trans, DUNDI_COMMAND_ENCRYPT, 0, trans->lasttrans->h->cmdresp & 0x80, &ied); - peer->sentfullkey = 1; - } - } - } - break; - case DUNDI_COMMAND_ENCRYPT: - if (!encrypted) { - /* No nested encryption! */ - if ((trans->iseqno == 1) && !trans->oseqno) { - if (!ies.eids[0] || !(peer = find_peer(ies.eids[0])) || - ((!ies.encsharedkey || !ies.encsig) && !ies.keycrc32) || - (check_key(peer, ies.encsharedkey, ies.encsig, ies.keycrc32) < 1)) { - if (!final) { - dundi_send(trans, DUNDI_COMMAND_ENCREJ, 0, 1, NULL); - } - break; - } - apply_peer(trans, peer); - /* Key passed, use new contexts for this session */ - trans->ecx = peer->them_ecx; - trans->dcx = peer->them_dcx; - } - if (ast_test_flag(trans, FLAG_ENCRYPT) && ies.encblock && ies.enclen) { - struct dundi_hdr *dhdr; - unsigned char decoded[MAX_PACKET_SIZE]; - int ddatalen; - ddatalen = sizeof(decoded); - dhdr = dundi_decrypt(trans, decoded, &ddatalen, hdr, ies.encblock, ies.enclen); - if (dhdr) { - /* Handle decrypted response */ - if (dundidebug) - dundi_showframe(dhdr, 3, &trans->addr, ddatalen - sizeof(struct dundi_hdr)); - handle_command_response(trans, dhdr, ddatalen - sizeof(struct dundi_hdr), 1); - /* Carry back final flag */ - hdr->cmdresp |= dhdr->cmdresp & 0x80; - break; - } else - ast_log(LOG_DEBUG, "Ouch, decrypt failed :(\n"); - } - } - if (!final) { - /* Turn off encryption */ - ast_clear_flag(trans, FLAG_ENCRYPT); - dundi_send(trans, DUNDI_COMMAND_ENCREJ, 0, 1, NULL); - } - break; - default: - /* Send unknown command if we don't know it, with final flag IFF it's the - first command in the dialog and only if we haven't recieved final notification */ - if (!final) { - dundi_ie_append_byte(&ied, DUNDI_IE_UNKNOWN, cmd); - dundi_send(trans, DUNDI_COMMAND_UNKNOWN, 0, !hdr->oseqno, &ied); - } - } - return 0; -} - -static void destroy_packet(struct dundi_packet *pack, int needfree); -static void destroy_packets(struct dundi_packet *p) -{ - struct dundi_packet *prev; - while(p) { - prev = p; - p = p->next; - if (prev->retransid > -1) - ast_sched_del(sched, prev->retransid); - free(prev); - } -} - - -static int ack_trans(struct dundi_transaction *trans, int iseqno) -{ - /* Ack transmitted packet corresponding to iseqno */ - struct dundi_packet *pack; - pack = trans->packets; - while(pack) { - if ((pack->h->oseqno + 1) % 255 == iseqno) { - destroy_packet(pack, 0); - if (trans->lasttrans) { - ast_log(LOG_WARNING, "Whoa, there was still a last trans?\n"); - destroy_packets(trans->lasttrans); - } - trans->lasttrans = pack; - if (trans->autokillid > -1) - ast_sched_del(sched, trans->autokillid); - trans->autokillid = -1; - return 1; - } - pack = pack->next; - } - return 0; -} - -static int handle_frame(struct dundi_hdr *h, struct sockaddr_in *sin, int datalen) -{ - struct dundi_transaction *trans; - trans = find_transaction(h, sin); - if (!trans) { - dundi_reject(h, sin); - return 0; - } - /* Got a transaction, see where this header fits in */ - if (h->oseqno == trans->iseqno) { - /* Just what we were looking for... Anything but ack increments iseqno */ - if (ack_trans(trans, h->iseqno) && ast_test_flag(trans, FLAG_FINAL)) { - /* If final, we're done */ - destroy_trans(trans, 0); - return 0; - } - if (h->cmdresp != DUNDI_COMMAND_ACK) { - trans->oiseqno = trans->iseqno; - trans->iseqno++; - handle_command_response(trans, h, datalen, 0); - } - if (trans->aseqno != trans->iseqno) { - dundi_ack(trans, h->cmdresp & 0x80); - trans->aseqno = trans->iseqno; - } - /* Delete any saved last transmissions */ - destroy_packets(trans->lasttrans); - trans->lasttrans = NULL; - if (h->cmdresp & 0x80) { - /* Final -- destroy now */ - destroy_trans(trans, 0); - } - } else if (h->oseqno == trans->oiseqno) { - /* Last incoming sequence number -- send ACK without processing */ - dundi_ack(trans, 0); - } else { - /* Out of window -- simply drop */ - ast_log(LOG_DEBUG, "Dropping packet out of window!\n"); - } - return 0; -} - -static int socket_read(int *id, int fd, short events, void *cbdata) -{ - struct sockaddr_in sin; - int res; - struct dundi_hdr *h; - char buf[MAX_PACKET_SIZE]; - socklen_t len; - len = sizeof(sin); - res = recvfrom(netsocket, buf, sizeof(buf) - 1, 0,(struct sockaddr *) &sin, &len); - if (res < 0) { - if (errno != ECONNREFUSED) - ast_log(LOG_WARNING, "Error: %s\n", strerror(errno)); - return 1; - } - if (res < sizeof(struct dundi_hdr)) { - ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int)sizeof(struct dundi_hdr)); - return 1; - } - buf[res] = '\0'; - h = (struct dundi_hdr *)buf; - if (dundidebug) - dundi_showframe(h, 1, &sin, res - sizeof(struct dundi_hdr)); - ast_mutex_lock(&peerlock); - handle_frame(h, &sin, res - sizeof(struct dundi_hdr)); - ast_mutex_unlock(&peerlock); - return 1; -} - -static void build_secret(char *secret, int seclen) -{ - unsigned char tmp[16]; - char *s; - build_iv(tmp); - secret[0] = '\0'; - ast_base64encode(secret, tmp, sizeof(tmp), seclen); - /* Eliminate potential bad characters */ - while((s = strchr(secret, ';'))) *s = '+'; - while((s = strchr(secret, '/'))) *s = '+'; - while((s = strchr(secret, ':'))) *s = '+'; - while((s = strchr(secret, '@'))) *s = '+'; -} - - -static void save_secret(const char *newkey, const char *oldkey) -{ - char tmp[256]; - if (oldkey) - snprintf(tmp, sizeof(tmp), "%s;%s", oldkey, newkey); - else - snprintf(tmp, sizeof(tmp), "%s", newkey); - rotatetime = time(NULL) + DUNDI_SECRET_TIME; - ast_db_put(secretpath, "secret", tmp); - snprintf(tmp, sizeof(tmp), "%d", (int)rotatetime); - ast_db_put(secretpath, "secretexpiry", tmp); -} - -static void load_password(void) -{ - char *current=NULL; - char *last=NULL; - char tmp[256]; - time_t expired; - - ast_db_get(secretpath, "secretexpiry", tmp, sizeof(tmp)); - if (sscanf(tmp, "%d", (int *)&expired) == 1) { - ast_db_get(secretpath, "secret", tmp, sizeof(tmp)); - current = strchr(tmp, ';'); - if (!current) - current = tmp; - else { - *current = '\0'; - current++; - }; - if ((time(NULL) - expired) < 0) { - if ((expired - time(NULL)) > DUNDI_SECRET_TIME) - expired = time(NULL) + DUNDI_SECRET_TIME; - } else if ((time(NULL) - (expired + DUNDI_SECRET_TIME)) < 0) { - last = current; - current = NULL; - } else { - last = NULL; - current = NULL; - } - } - if (current) { - /* Current key is still valid, just setup rotatation properly */ - ast_copy_string(cursecret, current, sizeof(cursecret)); - rotatetime = expired; - } else { - /* Current key is out of date, rotate or eliminate all together */ - build_secret(cursecret, sizeof(cursecret)); - save_secret(cursecret, last); - } -} - -static void check_password(void) -{ - char oldsecret[80]; - time_t now; - - time(&now); -#if 0 - printf("%ld/%ld\n", now, rotatetime); -#endif - if ((now - rotatetime) >= 0) { - /* Time to rotate keys */ - ast_copy_string(oldsecret, cursecret, sizeof(oldsecret)); - build_secret(cursecret, sizeof(cursecret)); - save_secret(cursecret, oldsecret); - } -} - -static void *network_thread(void *ignore) -{ - /* Our job is simple: Send queued messages, retrying if necessary. Read frames - from the network, and queue them for delivery to the channels */ - int res; - /* Establish I/O callback for socket read */ - ast_io_add(io, netsocket, socket_read, AST_IO_IN, NULL); - for(;;) { - res = ast_sched_wait(sched); - if ((res > 1000) || (res < 0)) - res = 1000; - res = ast_io_wait(io, res); - if (res >= 0) { - ast_mutex_lock(&peerlock); - ast_sched_runq(sched); - ast_mutex_unlock(&peerlock); - } - check_password(); - } - return NULL; -} - -static void *process_precache(void *ign) -{ - struct dundi_precache_queue *qe; - time_t now; - char context[256]; - char number[256]; - int run; - for (;;) { - time(&now); - run = 0; - ast_mutex_lock(&pclock); - if (pcq) { - if (!pcq->expiration) { - /* Gone... Remove... */ - qe = pcq; - pcq = pcq->next; - free(qe); - } else if (pcq->expiration < now) { - /* Process this entry */ - pcq->expiration = 0; - ast_copy_string(context, pcq->context, sizeof(context)); - ast_copy_string(number, pcq->number, sizeof(number)); - run = 1; - } - } - ast_mutex_unlock(&pclock); - if (run) { - dundi_precache(context, number); - } else - sleep(1); - } - return NULL; -} - -static int start_network_thread(void) -{ - ast_pthread_create(&netthreadid, NULL, network_thread, NULL); - ast_pthread_create(&precachethreadid, NULL, process_precache, NULL); - return 0; -} - -static int dundi_do_debug(int fd, int argc, char *argv[]) -{ - if (argc != 2) - return RESULT_SHOWUSAGE; - dundidebug = 1; - ast_cli(fd, "DUNDi Debugging Enabled\n"); - return RESULT_SUCCESS; -} - -static int dundi_do_store_history(int fd, int argc, char *argv[]) -{ - if (argc != 3) - return RESULT_SHOWUSAGE; - global_storehistory = 1; - ast_cli(fd, "DUNDi History Storage Enabled\n"); - return RESULT_SUCCESS; -} - -static int dundi_flush(int fd, int argc, char *argv[]) -{ - int stats=0; - if ((argc < 2) || (argc > 3)) - return RESULT_SHOWUSAGE; - if (argc > 2) { - if (!strcasecmp(argv[2], "stats")) - stats = 1; - else - return RESULT_SHOWUSAGE; - } - if (stats) { - /* Flush statistics */ - struct dundi_peer *p; - int x; - ast_mutex_lock(&peerlock); - p = peers; - while(p) { - for (x=0;x<DUNDI_TIMING_HISTORY;x++) { - if (p->lookups[x]) - free(p->lookups[x]); - p->lookups[x] = NULL; - p->lookuptimes[x] = 0; - } - p->avgms = 0; - p = p->next; - } - ast_mutex_unlock(&peerlock); - } else { - ast_db_deltree("dundi/cache", NULL); - ast_cli(fd, "DUNDi Cache Flushed\n"); - } - return RESULT_SUCCESS; -} - -static int dundi_no_debug(int fd, int argc, char *argv[]) -{ - if (argc != 3) - return RESULT_SHOWUSAGE; - dundidebug = 0; - ast_cli(fd, "DUNDi Debugging Disabled\n"); - return RESULT_SUCCESS; -} - -static int dundi_no_store_history(int fd, int argc, char *argv[]) -{ - if (argc != 4) - return RESULT_SHOWUSAGE; - global_storehistory = 0; - ast_cli(fd, "DUNDi History Storage Disabled\n"); - return RESULT_SUCCESS; -} - -static char *model2str(int model) -{ - switch(model) { - case DUNDI_MODEL_INBOUND: - return "Inbound"; - case DUNDI_MODEL_OUTBOUND: - return "Outbound"; - case DUNDI_MODEL_SYMMETRIC: - return "Symmetric"; - default: - return "Unknown"; - } -} - -static char *complete_peer_helper(char *line, char *word, int pos, int state, int rpos) -{ - int which=0; - char *ret; - struct dundi_peer *p; - char eid_str[20]; - if (pos != rpos) - return NULL; - ast_mutex_lock(&peerlock); - p = peers; - while(p) { - if (!strncasecmp(word, dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid), strlen(word))) { - if (++which > state) - break; - } - p = p->next; - } - if (p) { - ret = strdup(dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid)); - } else - ret = NULL; - ast_mutex_unlock(&peerlock); - return ret; -} - -static char *complete_peer_4(char *line, char *word, int pos, int state) -{ - return complete_peer_helper(line, word, pos, state, 3); -} - -static int rescomp(const void *a, const void *b) -{ - const struct dundi_result *resa, *resb; - resa = a; - resb = b; - if (resa->weight < resb->weight) - return -1; - if (resa->weight > resb->weight) - return 1; - return 0; -} - -static void sort_results(struct dundi_result *results, int count) -{ - qsort(results, count, sizeof(results[0]), rescomp); -} - -static int dundi_do_lookup(int fd, int argc, char *argv[]) -{ - int res; - char tmp[256]; - char fs[80] = ""; - char *context; - int x; - int bypass = 0; - struct dundi_result dr[MAX_RESULTS]; - struct timeval start; - if ((argc < 3) || (argc > 4)) - return RESULT_SHOWUSAGE; - if (argc > 3) { - if (!strcasecmp(argv[3], "bypass")) - bypass=1; - else - return RESULT_SHOWUSAGE; - } - ast_copy_string(tmp, argv[2], sizeof(tmp)); - context = strchr(tmp, '@'); - if (context) { - *context = '\0'; - context++; - } - start = ast_tvnow(); - res = dundi_lookup(dr, MAX_RESULTS, NULL, context, tmp, bypass); - - if (res < 0) - ast_cli(fd, "DUNDi lookup returned error.\n"); - else if (!res) - ast_cli(fd, "DUNDi lookup returned no results.\n"); - else - sort_results(dr, res); - for (x=0;x<res;x++) { - ast_cli(fd, "%3d. %5d %s/%s (%s)\n", x + 1, dr[x].weight, dr[x].tech, dr[x].dest, dundi_flags2str(fs, sizeof(fs), dr[x].flags)); - ast_cli(fd, " from %s, expires in %d s\n", dr[x].eid_str, dr[x].expiration); - } - ast_cli(fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start)); - return RESULT_SUCCESS; -} - -static int dundi_do_precache(int fd, int argc, char *argv[]) -{ - int res; - char tmp[256]; - char *context; - struct timeval start; - if ((argc < 3) || (argc > 3)) - return RESULT_SHOWUSAGE; - ast_copy_string(tmp, argv[2], sizeof(tmp)); - context = strchr(tmp, '@'); - if (context) { - *context = '\0'; - context++; - } - start = ast_tvnow(); - res = dundi_precache(context, tmp); - - if (res < 0) - ast_cli(fd, "DUNDi precache returned error.\n"); - else if (!res) - ast_cli(fd, "DUNDi precache returned no error.\n"); - ast_cli(fd, "DUNDi lookup completed in %d ms\n", ast_tvdiff_ms(ast_tvnow(), start)); - return RESULT_SUCCESS; -} - -static int dundi_do_query(int fd, int argc, char *argv[]) -{ - int res; - char tmp[256]; - char *context; - dundi_eid eid; - struct dundi_entity_info dei; - if ((argc < 3) || (argc > 3)) - return RESULT_SHOWUSAGE; - if (dundi_str_to_eid(&eid, argv[2])) { - ast_cli(fd, "'%s' is not a valid EID!\n", argv[2]); - return RESULT_SHOWUSAGE; - } - ast_copy_string(tmp, argv[2], sizeof(tmp)); - context = strchr(tmp, '@'); - if (context) { - *context = '\0'; - context++; - } - res = dundi_query_eid(&dei, context, eid); - if (res < 0) - ast_cli(fd, "DUNDi Query EID returned error.\n"); - else if (!res) - ast_cli(fd, "DUNDi Query EID returned no results.\n"); - else { - ast_cli(fd, "DUNDi Query EID succeeded:\n"); - ast_cli(fd, "Department: %s\n", dei.orgunit); - ast_cli(fd, "Organization: %s\n", dei.org); - ast_cli(fd, "City/Locality: %s\n", dei.locality); - ast_cli(fd, "State/Province: %s\n", dei.stateprov); - ast_cli(fd, "Country: %s\n", dei.country); - ast_cli(fd, "E-mail: %s\n", dei.email); - ast_cli(fd, "Phone: %s\n", dei.phone); - ast_cli(fd, "IP Address: %s\n", dei.ipaddr); - } - return RESULT_SUCCESS; -} - -static int dundi_show_peer(int fd, int argc, char *argv[]) -{ - struct dundi_peer *peer; - struct permission *p; - char *order; - char iabuf[INET_ADDRSTRLEN]; - char eid_str[20]; - int x, cnt; - - if (argc != 4) - return RESULT_SHOWUSAGE; - ast_mutex_lock(&peerlock); - peer = peers; - while(peer) { - if (!strcasecmp(dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), argv[3])) - break; - peer = peer->next; - } - if (peer) { - switch(peer->order) { - case 0: - order = "Primary"; - break; - case 1: - order = "Secondary"; - break; - case 2: - order = "Tertiary"; - break; - case 3: - order = "Quartiary"; - break; - default: - order = "Unknown"; - } - ast_cli(fd, "Peer: %s\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); - ast_cli(fd, "Model: %s\n", model2str(peer->model)); - ast_cli(fd, "Host: %s\n", peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "<Unspecified>"); - ast_cli(fd, "Dynamic: %s\n", peer->dynamic ? "yes" : "no"); - ast_cli(fd, "KeyPend: %s\n", peer->keypending ? "yes" : "no"); - ast_cli(fd, "Reg: %s\n", peer->registerid < 0 ? "No" : "Yes"); - ast_cli(fd, "In Key: %s\n", ast_strlen_zero(peer->inkey) ? "<None>" : peer->inkey); - ast_cli(fd, "Out Key: %s\n", ast_strlen_zero(peer->outkey) ? "<None>" : peer->outkey); - if (peer->include) { - ast_cli(fd, "Include logic%s:\n", peer->model & DUNDI_MODEL_OUTBOUND ? "" : " (IGNORED)"); - } - p = peer->include; - while(p) { - ast_cli(fd, "-- %s %s\n", p->allow ? "include" : "do not include", p->name); - p = p->next; - } - if (peer->permit) { - ast_cli(fd, "Query logic%s:\n", peer->model & DUNDI_MODEL_INBOUND ? "" : " (IGNORED)"); - } - p = peer->permit; - while(p) { - ast_cli(fd, "-- %s %s\n", p->allow ? "permit" : "deny", p->name); - p = p->next; - } - cnt = 0; - for (x=0;x<DUNDI_TIMING_HISTORY;x++) { - if (peer->lookups[x]) { - if (!cnt) - ast_cli(fd, "Last few query times:\n"); - ast_cli(fd, "-- %d. %s (%d ms)\n", x + 1, peer->lookups[x], peer->lookuptimes[x]); - cnt++; - } - } - if (cnt) - ast_cli(fd, "Average query time: %d ms\n", peer->avgms); - } else - ast_cli(fd, "No such peer '%s'\n", argv[3]); - ast_mutex_unlock(&peerlock); - return RESULT_SUCCESS; -} - -static int dundi_show_peers(int fd, int argc, char *argv[]) -{ -#define FORMAT2 "%-20.20s %-15.15s %-10.10s %-8.8s %-15.15s\n" -#define FORMAT "%-20.20s %-15.15s %s %-10.10s %-8.8s %-15.15s\n" - struct dundi_peer *peer; - char iabuf[INET_ADDRSTRLEN]; - int registeredonly=0; - char avgms[20]; - char eid_str[20]; - int online_peers = 0; - int offline_peers = 0; - int unmonitored_peers = 0; - int total_peers = 0; - - if ((argc != 3) && (argc != 4) && (argc != 5)) - return RESULT_SHOWUSAGE; - if ((argc == 4)) { - if (!strcasecmp(argv[3], "registered")) { - registeredonly = 1; - } else - return RESULT_SHOWUSAGE; - } - ast_mutex_lock(&peerlock); - ast_cli(fd, FORMAT2, "EID", "Host", "Model", "AvgTime", "Status"); - for (peer = peers;peer;peer = peer->next) { - char status[20]; - int print_line = -1; - char srch[2000]; - total_peers++; - if (registeredonly && !peer->addr.sin_addr.s_addr) - continue; - if (peer->maxms) { - if (peer->lastms < 0) { - strcpy(status, "UNREACHABLE"); - offline_peers++; - } - else if (peer->lastms > peer->maxms) { - snprintf(status, sizeof(status), "LAGGED (%d ms)", peer->lastms); - offline_peers++; - } - else if (peer->lastms) { - snprintf(status, sizeof(status), "OK (%d ms)", peer->lastms); - online_peers++; - } - else { - strcpy(status, "UNKNOWN"); - offline_peers++; - } - } else { - strcpy(status, "Unmonitored"); - unmonitored_peers++; - } - if (peer->avgms) - snprintf(avgms, sizeof(avgms), "%d ms", peer->avgms); - else - strcpy(avgms, "Unavail"); - snprintf(srch, sizeof(srch), FORMAT, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), - peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)", - peer->dynamic ? "(D)" : "(S)", model2str(peer->model), avgms, status); - - if (argc == 5) { - if (!strcasecmp(argv[3],"include") && strstr(srch,argv[4])) { - print_line = -1; - } else if (!strcasecmp(argv[3],"exclude") && !strstr(srch,argv[4])) { - print_line = 1; - } else if (!strcasecmp(argv[3],"begin") && !strncasecmp(srch,argv[4],strlen(argv[4]))) { - print_line = -1; - } else { - print_line = 0; - } - } - - if (print_line) { - ast_cli(fd, FORMAT, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), - peer->addr.sin_addr.s_addr ? ast_inet_ntoa(iabuf, sizeof(iabuf), peer->addr.sin_addr) : "(Unspecified)", - peer->dynamic ? "(D)" : "(S)", model2str(peer->model), avgms, status); - } - } - ast_cli(fd, "%d dundi peers [%d online, %d offline, %d unmonitored]\n", total_peers, online_peers, offline_peers, unmonitored_peers); - ast_mutex_unlock(&peerlock); - return RESULT_SUCCESS; -#undef FORMAT -#undef FORMAT2 -} - -static int dundi_show_trans(int fd, int argc, char *argv[]) -{ -#define FORMAT2 "%-22.22s %-5.5s %-5.5s %-3.3s %-3.3s %-3.3s\n" -#define FORMAT "%-16.16s:%5d %-5.5d %-5.5d %-3.3d %-3.3d %-3.3d\n" - struct dundi_transaction *trans; - char iabuf[INET_ADDRSTRLEN]; - if (argc != 3) - return RESULT_SHOWUSAGE; - ast_mutex_lock(&peerlock); - ast_cli(fd, FORMAT2, "Remote", "Src", "Dst", "Tx", "Rx", "Ack"); - for (trans = alltrans;trans;trans = trans->allnext) { - ast_cli(fd, FORMAT, ast_inet_ntoa(iabuf, sizeof(iabuf), trans->addr.sin_addr), - ntohs(trans->addr.sin_port), trans->strans, trans->dtrans, trans->oseqno, trans->iseqno, trans->aseqno); - } - ast_mutex_unlock(&peerlock); - return RESULT_SUCCESS; -#undef FORMAT -#undef FORMAT2 -} - -static int dundi_show_entityid(int fd, int argc, char *argv[]) -{ - char eid_str[20]; - if (argc != 3) - return RESULT_SHOWUSAGE; - ast_mutex_lock(&peerlock); - dundi_eid_to_str(eid_str, sizeof(eid_str), &global_eid); - ast_mutex_unlock(&peerlock); - ast_cli(fd, "Global EID for this system is '%s'\n", eid_str); - return RESULT_SUCCESS; -} - -static int dundi_show_requests(int fd, int argc, char *argv[]) -{ -#define FORMAT2 "%-15s %-15s %-15s %-3.3s %-3.3s\n" -#define FORMAT "%-15s %-15s %-15s %-3.3d %-3.3d\n" - struct dundi_request *req; - char eidstr[20]; - if (argc != 3) - return RESULT_SHOWUSAGE; - ast_mutex_lock(&peerlock); - ast_cli(fd, FORMAT2, "Number", "Context", "Root", "Max", "Rsp"); - for (req = requests;req;req = req->next) { - ast_cli(fd, FORMAT, req->number, req->dcontext, - dundi_eid_zero(&req->root_eid) ? "<unspecified>" : dundi_eid_to_str(eidstr, sizeof(eidstr), &req->root_eid), req->maxcount, req->respcount); - } - ast_mutex_unlock(&peerlock); - return RESULT_SUCCESS; -#undef FORMAT -#undef FORMAT2 -} - -/* Grok-a-dial DUNDi */ - -static int dundi_show_mappings(int fd, int argc, char *argv[]) -{ -#define FORMAT2 "%-12.12s %-7.7s %-12.12s %-10.10s %-5.5s %-25.25s\n" -#define FORMAT "%-12.12s %-7d %-12.12s %-10.10s %-5.5s %-25.25s\n" - struct dundi_mapping *map; - char fs[256]; - if (argc != 3) - return RESULT_SHOWUSAGE; - ast_mutex_lock(&peerlock); - ast_cli(fd, FORMAT2, "DUNDi Cntxt", "Weight", "Local Cntxt", "Options", "Tech", "Destination"); - for (map = mappings;map;map = map->next) { - ast_cli(fd, FORMAT, map->dcontext, map->weight, - ast_strlen_zero(map->lcontext) ? "<none>" : map->lcontext, - dundi_flags2str(fs, sizeof(fs), map->options), tech2str(map->tech), map->dest); - } - ast_mutex_unlock(&peerlock); - return RESULT_SUCCESS; -#undef FORMAT -#undef FORMAT2 -} - -static int dundi_show_precache(int fd, int argc, char *argv[]) -{ -#define FORMAT2 "%-12.12s %-12.12s %-10.10s\n" -#define FORMAT "%-12.12s %-12.12s %02d:%02d:%02d\n" - struct dundi_precache_queue *qe; - int h,m,s; - time_t now; - - if (argc != 3) - return RESULT_SHOWUSAGE; - time(&now); - ast_mutex_lock(&pclock); - ast_cli(fd, FORMAT2, "Number", "Context", "Expiration"); - for (qe = pcq;qe;qe = qe->next) { - s = qe->expiration - now; - h = s / 3600; - s = s % 3600; - m = s / 60; - s = s % 60; - ast_cli(fd, FORMAT, qe->number, qe->context, h,m,s); - } - ast_mutex_unlock(&pclock); - return RESULT_SUCCESS; -#undef FORMAT -#undef FORMAT2 -} - -static char debug_usage[] = -"Usage: dundi debug\n" -" Enables dumping of DUNDi packets for debugging purposes\n"; - -static char no_debug_usage[] = -"Usage: dundi no debug\n" -" Disables dumping of DUNDi packets for debugging purposes\n"; - -static char store_history_usage[] = -"Usage: dundi store history\n" -" Enables storing of DUNDi requests and times for debugging\n" -"purposes\n"; - -static char no_store_history_usage[] = -"Usage: dundi no store history\n" -" Disables storing of DUNDi requests and times for debugging\n" -"purposes\n"; - -static char show_peers_usage[] = -"Usage: dundi show peers\n" -" Lists all known DUNDi peers.\n"; - -static char show_trans_usage[] = -"Usage: dundi show trans\n" -" Lists all known DUNDi transactions.\n"; - -static char show_mappings_usage[] = -"Usage: dundi show mappings\n" -" Lists all known DUNDi mappings.\n"; - -static char show_precache_usage[] = -"Usage: dundi show precache\n" -" Lists all known DUNDi scheduled precache updates.\n"; - -static char show_entityid_usage[] = -"Usage: dundi show entityid\n" -" Displays the global entityid for this host.\n"; - -static char show_peer_usage[] = -"Usage: dundi show peer [peer]\n" -" Provide a detailed description of a specifid DUNDi peer.\n"; - -static char show_requests_usage[] = -"Usage: dundi show requests\n" -" Lists all known pending DUNDi requests.\n"; - -static char lookup_usage[] = -"Usage: dundi lookup <number>[@context] [bypass]\n" -" Lookup the given number within the given DUNDi context\n" -"(or e164 if none is specified). Bypasses cache if 'bypass'\n" -"keyword is specified.\n"; - -static char precache_usage[] = -"Usage: dundi precache <number>[@context]\n" -" Lookup the given number within the given DUNDi context\n" -"(or e164 if none is specified) and precaches the results to any\n" -"upstream DUNDi push servers.\n"; - -static char query_usage[] = -"Usage: dundi query <entity>[@context]\n" -" Attempts to retrieve contact information for a specific\n" -"DUNDi entity identifier (EID) within a given DUNDi context (or\n" -"e164 if none is specified).\n"; - -static char flush_usage[] = -"Usage: dundi flush [stats]\n" -" Flushes DUNDi answer cache, used primarily for debug. If\n" -"'stats' is present, clears timer statistics instead of normal\n" -"operation.\n"; - -static struct ast_cli_entry cli_debug = - { { "dundi", "debug", NULL }, dundi_do_debug, "Enable DUNDi debugging", debug_usage }; - -static struct ast_cli_entry cli_store_history = - { { "dundi", "store", "history", NULL }, dundi_do_store_history, "Enable DUNDi historic records", store_history_usage }; - -static struct ast_cli_entry cli_no_store_history = - { { "dundi", "no", "store", "history", NULL }, dundi_no_store_history, "Disable DUNDi historic records", no_store_history_usage }; - -static struct ast_cli_entry cli_flush = - { { "dundi", "flush", NULL }, dundi_flush, "Flush DUNDi cache", flush_usage }; - -static struct ast_cli_entry cli_no_debug = - { { "dundi", "no", "debug", NULL }, dundi_no_debug, "Disable DUNDi debugging", no_debug_usage }; - -static struct ast_cli_entry cli_show_peers = - { { "dundi", "show", "peers", NULL }, dundi_show_peers, "Show defined DUNDi peers", show_peers_usage }; - -static struct ast_cli_entry cli_show_trans = - { { "dundi", "show", "trans", NULL }, dundi_show_trans, "Show active DUNDi transactions", show_trans_usage }; - -static struct ast_cli_entry cli_show_entityid = - { { "dundi", "show", "entityid", NULL }, dundi_show_entityid, "Display Global Entity ID", show_entityid_usage }; - -static struct ast_cli_entry cli_show_mappings = - { { "dundi", "show", "mappings", NULL }, dundi_show_mappings, "Show DUNDi mappings", show_mappings_usage }; - -static struct ast_cli_entry cli_show_precache = - { { "dundi", "show", "precache", NULL }, dundi_show_precache, "Show DUNDi precache", show_precache_usage }; - -static struct ast_cli_entry cli_show_requests = - { { "dundi", "show", "requests", NULL }, dundi_show_requests, "Show DUNDi requests", show_requests_usage }; - -static struct ast_cli_entry cli_show_peer = - { { "dundi", "show", "peer", NULL }, dundi_show_peer, "Show info on a specific DUNDi peer", show_peer_usage, complete_peer_4 }; - -static struct ast_cli_entry cli_lookup = - { { "dundi", "lookup", NULL }, dundi_do_lookup, "Lookup a number in DUNDi", lookup_usage }; - -static struct ast_cli_entry cli_precache = - { { "dundi", "precache", NULL }, dundi_do_precache, "Precache a number in DUNDi", precache_usage }; - -static struct ast_cli_entry cli_queryeid = - { { "dundi", "query", NULL }, dundi_do_query, "Query a DUNDi EID", query_usage }; - -STANDARD_LOCAL_USER; - -LOCAL_USER_DECL; - -static struct dundi_transaction *create_transaction(struct dundi_peer *p) -{ - struct dundi_transaction *trans; - int tid; - - /* Don't allow creation of transactions to non-registered peers */ - if (p && !p->addr.sin_addr.s_addr) - return NULL; - tid = get_trans_id(); - if (tid < 1) - return NULL; - trans = malloc(sizeof(struct dundi_transaction)); - if (trans) { - memset(trans, 0, sizeof(struct dundi_transaction)); - if (global_storehistory) { - trans->start = ast_tvnow(); - ast_set_flag(trans, FLAG_STOREHIST); - } - trans->retranstimer = DUNDI_DEFAULT_RETRANS_TIMER; - trans->autokillid = -1; - if (p) { - apply_peer(trans, p); - if (!p->sentfullkey) - ast_set_flag(trans, FLAG_SENDFULLKEY); - } - trans->strans = tid; - trans->allnext = alltrans; - alltrans = trans; - } - return trans; -} - -static int dundi_xmit(struct dundi_packet *pack) -{ - int res; - char iabuf[INET_ADDRSTRLEN]; - if (dundidebug) - dundi_showframe(pack->h, 0, &pack->parent->addr, pack->datalen - sizeof(struct dundi_hdr)); - res = sendto(netsocket, pack->data, pack->datalen, 0, (struct sockaddr *)&pack->parent->addr, sizeof(pack->parent->addr)); - if (res < 0) { - ast_log(LOG_WARNING, "Failed to transmit to '%s:%d': %s\n", - ast_inet_ntoa(iabuf, sizeof(iabuf), pack->parent->addr.sin_addr), - ntohs(pack->parent->addr.sin_port), strerror(errno)); - } - if (res > 0) - res = 0; - return res; -} - -static void destroy_packet(struct dundi_packet *pack, int needfree) -{ - struct dundi_packet *prev, *cur; - if (pack->parent) { - prev = NULL; - cur = pack->parent->packets; - while(cur) { - if (cur == pack) { - if (prev) - prev->next = cur->next; - else - pack->parent->packets = cur->next; - break; - } - prev = cur; - cur = cur->next; - } - } - if (pack->retransid > -1) - ast_sched_del(sched, pack->retransid); - if (needfree) - free(pack); - else { - pack->retransid = -1; - pack->next = NULL; - } -} - -static void destroy_trans(struct dundi_transaction *trans, int fromtimeout) -{ - struct dundi_transaction *cur, *prev; - struct dundi_peer *peer; - int ms; - int x; - int cnt; - char eid_str[20]; - if (ast_test_flag(trans, FLAG_ISREG | FLAG_ISQUAL | FLAG_STOREHIST)) { - peer = peers; - while (peer) { - if (peer->regtrans == trans) - peer->regtrans = NULL; - if (peer->keypending == trans) - peer->keypending = NULL; - if (peer->qualtrans == trans) { - if (fromtimeout) { - if (peer->lastms > -1) - ast_log(LOG_NOTICE, "Peer '%s' has become UNREACHABLE!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); - peer->lastms = -1; - } else { - ms = ast_tvdiff_ms(ast_tvnow(), peer->qualtx); - if (ms < 1) - ms = 1; - if (ms < peer->maxms) { - if ((peer->lastms >= peer->maxms) || (peer->lastms < 0)) - ast_log(LOG_NOTICE, "Peer '%s' has become REACHABLE!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); - } else if (peer->lastms < peer->maxms) { - ast_log(LOG_NOTICE, "Peer '%s' has become TOO LAGGED (%d ms)\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), ms); - } - peer->lastms = ms; - } - peer->qualtrans = NULL; - } - if (ast_test_flag(trans, FLAG_STOREHIST)) { - if (trans->parent && !ast_strlen_zero(trans->parent->number)) { - if (!dundi_eid_cmp(&trans->them_eid, &peer->eid)) { - peer->avgms = 0; - cnt = 0; - if (peer->lookups[DUNDI_TIMING_HISTORY-1]) - free(peer->lookups[DUNDI_TIMING_HISTORY-1]); - for (x=DUNDI_TIMING_HISTORY-1;x>0;x--) { - peer->lookuptimes[x] = peer->lookuptimes[x-1]; - peer->lookups[x] = peer->lookups[x-1]; - if (peer->lookups[x]) { - peer->avgms += peer->lookuptimes[x]; - cnt++; - } - } - peer->lookuptimes[0] = ast_tvdiff_ms(ast_tvnow(), trans->start); - peer->lookups[0] = malloc(strlen(trans->parent->number) + strlen(trans->parent->dcontext) + 2); - if (peer->lookups[0]) { - sprintf(peer->lookups[0], "%s@%s", trans->parent->number, trans->parent->dcontext); - peer->avgms += peer->lookuptimes[0]; - cnt++; - } - if (cnt) - peer->avgms /= cnt; - } - } - } - peer = peer->next; - } - } - if (trans->parent) { - /* Unlink from parent if appropriate */ - prev = NULL; - cur = trans->parent->trans; - while(cur) { - if (cur == trans) { - if (prev) - prev->next = trans->next; - else - trans->parent->trans = trans->next; - break; - } - prev = cur; - cur = cur->next; - } - if (!trans->parent->trans) { - /* Wake up sleeper */ - if (trans->parent->pfds[1] > -1) { - write(trans->parent->pfds[1], "killa!", 6); - } - } - } - /* Unlink from all trans */ - prev = NULL; - cur = alltrans; - while(cur) { - if (cur == trans) { - if (prev) - prev->allnext = trans->allnext; - else - alltrans = trans->allnext; - break; - } - prev = cur; - cur = cur->allnext; - } - destroy_packets(trans->packets); - destroy_packets(trans->lasttrans); - trans->packets = NULL; - trans->lasttrans = NULL; - if (trans->autokillid > -1) - ast_sched_del(sched, trans->autokillid); - trans->autokillid = -1; - if (trans->thread) { - /* If used by a thread, mark as dead and be done */ - ast_set_flag(trans, FLAG_DEAD); - } else - free(trans); -} - -static int dundi_rexmit(void *data) -{ - struct dundi_packet *pack; - char iabuf[INET_ADDRSTRLEN]; - int res; - ast_mutex_lock(&peerlock); - pack = data; - if (pack->retrans < 1) { - pack->retransid = -1; - if (!ast_test_flag(pack->parent, FLAG_ISQUAL)) - ast_log(LOG_NOTICE, "Max retries exceeded to host '%s:%d' msg %d on call %d\n", - ast_inet_ntoa(iabuf, sizeof(iabuf), pack->parent->addr.sin_addr), - ntohs(pack->parent->addr.sin_port), pack->h->oseqno, ntohs(pack->h->strans)); - destroy_trans(pack->parent, 1); - res = 0; - } else { - /* Decrement retransmission, try again */ - pack->retrans--; - dundi_xmit(pack); - res = 1; - } - ast_mutex_unlock(&peerlock); - return res; -} - -static int dundi_send(struct dundi_transaction *trans, int cmdresp, int flags, int final, struct dundi_ie_data *ied) -{ - struct dundi_packet *pack; - int res; - int len; - char eid_str[20]; - len = sizeof(struct dundi_packet) + sizeof(struct dundi_hdr) + (ied ? ied->pos : 0); - /* Reserve enough space for encryption */ - if (ast_test_flag(trans, FLAG_ENCRYPT)) - len += 384; - pack = malloc(len); - if (pack) { - memset(pack, 0, len); - pack->h = (struct dundi_hdr *)(pack->data); - if (cmdresp != DUNDI_COMMAND_ACK) { - pack->retransid = ast_sched_add(sched, trans->retranstimer, dundi_rexmit, pack); - pack->retrans = DUNDI_DEFAULT_RETRANS - 1; - pack->next = trans->packets; - trans->packets = pack; - } - pack->parent = trans; - pack->h->strans = htons(trans->strans); - pack->h->dtrans = htons(trans->dtrans); - pack->h->iseqno = trans->iseqno; - pack->h->oseqno = trans->oseqno; - pack->h->cmdresp = cmdresp; - pack->datalen = sizeof(struct dundi_hdr); - if (ied) { - memcpy(pack->h->ies, ied->buf, ied->pos); - pack->datalen += ied->pos; - } - if (final) { - pack->h->cmdresp |= DUNDI_COMMAND_FINAL; - ast_set_flag(trans, FLAG_FINAL); - } - pack->h->cmdflags = flags; - if (cmdresp != DUNDI_COMMAND_ACK) { - trans->oseqno++; - trans->oseqno = trans->oseqno % 256; - } - trans->aseqno = trans->iseqno; - /* If we have their public key, encrypt */ - if (ast_test_flag(trans, FLAG_ENCRYPT)) { - switch(cmdresp) { - case DUNDI_COMMAND_REGREQ: - case DUNDI_COMMAND_REGRESPONSE: - case DUNDI_COMMAND_DPDISCOVER: - case DUNDI_COMMAND_DPRESPONSE: - case DUNDI_COMMAND_EIDQUERY: - case DUNDI_COMMAND_EIDRESPONSE: - case DUNDI_COMMAND_PRECACHERQ: - case DUNDI_COMMAND_PRECACHERP: - if (dundidebug) - dundi_showframe(pack->h, 2, &trans->addr, pack->datalen - sizeof(struct dundi_hdr)); - res = dundi_encrypt(trans, pack); - break; - default: - res = 0; - } - } else - res = 0; - if (!res) - res = dundi_xmit(pack); - if (res) - ast_log(LOG_NOTICE, "Failed to send packet to '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid)); - - if (cmdresp == DUNDI_COMMAND_ACK) - free(pack); - return res; - } - return -1; -} - -static int do_autokill(void *data) -{ - struct dundi_transaction *trans = data; - char eid_str[20]; - ast_log(LOG_NOTICE, "Transaction to '%s' took too long to ACK, destroying\n", - dundi_eid_to_str(eid_str, sizeof(eid_str), &trans->them_eid)); - trans->autokillid = -1; - destroy_trans(trans, 0); /* We could actually set it to 1 instead of 0, but we won't ;-) */ - return 0; -} - -static void dundi_ie_append_eid_appropriately(struct dundi_ie_data *ied, char *context, dundi_eid *eid, dundi_eid *us) -{ - struct dundi_peer *p; - if (!dundi_eid_cmp(eid, us)) { - dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid); - return; - } - ast_mutex_lock(&peerlock); - p = peers; - while(p) { - if (!dundi_eid_cmp(&p->eid, eid)) { - if (has_permission(p->include, context)) - dundi_ie_append_eid(ied, DUNDI_IE_EID_DIRECT, eid); - else - dundi_ie_append_eid(ied, DUNDI_IE_EID, eid); - break; - } - p = p->next; - } - if (!p) - dundi_ie_append_eid(ied, DUNDI_IE_EID, eid); - ast_mutex_unlock(&peerlock); -} - -static int dundi_discover(struct dundi_transaction *trans) -{ - struct dundi_ie_data ied; - int x; - if (!trans->parent) { - ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n"); - return -1; - } - memset(&ied, 0, sizeof(ied)); - dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION); - if (!dundi_eid_zero(&trans->us_eid)) - dundi_ie_append_eid(&ied, DUNDI_IE_EID_DIRECT, &trans->us_eid); - for (x=0;x<trans->eidcount;x++) - dundi_ie_append_eid_appropriately(&ied, trans->parent->dcontext, &trans->eids[x], &trans->us_eid); - dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number); - dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext); - dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl); - if (trans->parent->cbypass) - dundi_ie_append(&ied, DUNDI_IE_CACHEBYPASS); - if (trans->autokilltimeout) - trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans); - return dundi_send(trans, DUNDI_COMMAND_DPDISCOVER, 0, 0, &ied); -} - -static int precache_trans(struct dundi_transaction *trans, struct dundi_mapping *maps, int mapcount, int *minexp, int *foundanswers) -{ - struct dundi_ie_data ied; - int x, res; - int max = 999999; - int expiration = dundi_cache_time; - int ouranswers=0; - dundi_eid *avoid[1] = { NULL, }; - int direct[1] = { 0, }; - struct dundi_result dr[MAX_RESULTS]; - struct dundi_hint_metadata hmd; - if (!trans->parent) { - ast_log(LOG_WARNING, "Tried to discover a transaction with no parent?!?\n"); - return -1; - } - memset(&hmd, 0, sizeof(hmd)); - memset(&dr, 0, sizeof(dr)); - /* Look up the answers we're going to include */ - for (x=0;x<mapcount;x++) - ouranswers = dundi_lookup_local(dr, maps + x, trans->parent->number, &trans->us_eid, ouranswers, &hmd); - if (ouranswers < 0) - ouranswers = 0; - for (x=0;x<ouranswers;x++) { - if (dr[x].weight < max) - max = dr[x].weight; - } - if (max) { - /* If we do not have a canonical result, keep looking */ - res = dundi_lookup_internal(dr + ouranswers, MAX_RESULTS - ouranswers, NULL, trans->parent->dcontext, trans->parent->number, trans->ttl, 1, &hmd, &expiration, 0, 1, &trans->them_eid, avoid, direct); - if (res > 0) { - /* Append answer in result */ - ouranswers += res; - } - } - - if (ouranswers > 0) { - *foundanswers += ouranswers; - memset(&ied, 0, sizeof(ied)); - dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION); - if (!dundi_eid_zero(&trans->us_eid)) - dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid); - for (x=0;x<trans->eidcount;x++) - dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]); - dundi_ie_append_str(&ied, DUNDI_IE_CALLED_NUMBER, trans->parent->number); - dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext); - dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl); - for (x=0;x<ouranswers;x++) { - /* Add answers */ - if (dr[x].expiration && (expiration > dr[x].expiration)) - expiration = dr[x].expiration; - dundi_ie_append_answer(&ied, DUNDI_IE_ANSWER, &dr[x].eid, dr[x].techint, dr[x].flags, dr[x].weight, dr[x].dest); - } - dundi_ie_append_hint(&ied, DUNDI_IE_HINT, hmd.flags, hmd.exten); - dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, expiration); - if (trans->autokilltimeout) - trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans); - if (expiration < *minexp) - *minexp = expiration; - return dundi_send(trans, DUNDI_COMMAND_PRECACHERQ, 0, 0, &ied); - } else { - /* Oops, nothing to send... */ - destroy_trans(trans, 0); - return 0; - } -} - -static int dundi_query(struct dundi_transaction *trans) -{ - struct dundi_ie_data ied; - int x; - if (!trans->parent) { - ast_log(LOG_WARNING, "Tried to query a transaction with no parent?!?\n"); - return -1; - } - memset(&ied, 0, sizeof(ied)); - dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION); - if (!dundi_eid_zero(&trans->us_eid)) - dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->us_eid); - for (x=0;x<trans->eidcount;x++) - dundi_ie_append_eid(&ied, DUNDI_IE_EID, &trans->eids[x]); - dundi_ie_append_eid(&ied, DUNDI_IE_REQEID, &trans->parent->query_eid); - dundi_ie_append_str(&ied, DUNDI_IE_CALLED_CONTEXT, trans->parent->dcontext); - dundi_ie_append_short(&ied, DUNDI_IE_TTL, trans->ttl); - if (trans->autokilltimeout) - trans->autokillid = ast_sched_add(sched, trans->autokilltimeout, do_autokill, trans); - return dundi_send(trans, DUNDI_COMMAND_EIDQUERY, 0, 0, &ied); -} - -static int discover_transactions(struct dundi_request *dr) -{ - struct dundi_transaction *trans; - ast_mutex_lock(&peerlock); - trans = dr->trans; - while(trans) { - dundi_discover(trans); - trans = trans->next; - } - ast_mutex_unlock(&peerlock); - return 0; -} - -static int precache_transactions(struct dundi_request *dr, struct dundi_mapping *maps, int mapcount, int *expiration, int *foundanswers) -{ - struct dundi_transaction *trans, *transn; - /* Mark all as "in thread" so they don't disappear */ - ast_mutex_lock(&peerlock); - trans = dr->trans; - while(trans) { - if (trans->thread) - ast_log(LOG_WARNING, "This shouldn't happen, really...\n"); - trans->thread = 1; - trans = trans->next; - } - ast_mutex_unlock(&peerlock); - - trans = dr->trans; - while(trans) { - if (!ast_test_flag(trans, FLAG_DEAD)) - precache_trans(trans, maps, mapcount, expiration, foundanswers); - trans = trans->next; - } - - /* Cleanup any that got destroyed in the mean time */ - ast_mutex_lock(&peerlock); - trans = dr->trans; - while(trans) { - transn = trans->next; - trans->thread = 0; - if (ast_test_flag(trans, FLAG_DEAD)) { - ast_log(LOG_DEBUG, "Our transaction went away!\n"); - destroy_trans(trans, 0); - } - trans = transn; - } - ast_mutex_unlock(&peerlock); - return 0; -} - -static int query_transactions(struct dundi_request *dr) -{ - struct dundi_transaction *trans; - ast_mutex_lock(&peerlock); - trans = dr->trans; - while(trans) { - dundi_query(trans); - trans = trans->next; - } - ast_mutex_unlock(&peerlock); - return 0; -} - -static int optimize_transactions(struct dundi_request *dr, int order) -{ - /* Minimize the message propagation through DUNDi by - alerting the network to hops which should be not be considered */ - struct dundi_transaction *trans; - struct dundi_peer *peer; - dundi_eid tmp; - int x; - int needpush; - ast_mutex_lock(&peerlock); - trans = dr->trans; - while(trans) { - /* Pop off the true root */ - if (trans->eidcount) { - tmp = trans->eids[--trans->eidcount]; - needpush = 1; - } else { - tmp = trans->us_eid; - needpush = 0; - } - - peer = peers; - while(peer) { - if (has_permission(peer->include, dr->dcontext) && - dundi_eid_cmp(&peer->eid, &trans->them_eid) && - (peer->order <= order)) { - /* For each other transaction, make sure we don't - ask this EID about the others if they're not - already in the list */ - if (!dundi_eid_cmp(&tmp, &peer->eid)) - x = -1; - else { - for (x=0;x<trans->eidcount;x++) { - if (!dundi_eid_cmp(&trans->eids[x], &peer->eid)) - break; - } - } - if (x == trans->eidcount) { - /* Nope not in the list, if needed, add us at the end since we're the source */ - if (trans->eidcount < DUNDI_MAX_STACK - needpush) { - trans->eids[trans->eidcount++] = peer->eid; - /* Need to insert the real root (or us) at the bottom now as - a requirement now. */ - needpush = 1; - } - } - } - peer = peer->next; - } - /* If necessary, push the true root back on the end */ - if (needpush) - trans->eids[trans->eidcount++] = tmp; - trans = trans->next; - } - ast_mutex_unlock(&peerlock); - return 0; -} - -static int append_transaction(struct dundi_request *dr, struct dundi_peer *p, int ttl, dundi_eid *avoid[]) -{ - struct dundi_transaction *trans; - int x; - char eid_str[20]; - char eid_str2[20]; - /* Ignore if not registered */ - if (!p->addr.sin_addr.s_addr) - return 0; - if (p->maxms && ((p->lastms < 0) || (p->lastms >= p->maxms))) - return 0; - if (ast_strlen_zero(dr->number)) - ast_log(LOG_DEBUG, "Will query peer '%s' for '%s' (context '%s')\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid), dundi_eid_to_str(eid_str2, sizeof(eid_str2), &dr->query_eid), dr->dcontext); - else - ast_log(LOG_DEBUG, "Will query peer '%s' for '%s@%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &p->eid), dr->number, dr->dcontext); - trans = create_transaction(p); - if (!trans) - return -1; - trans->next = dr->trans; - trans->parent = dr; - trans->ttl = ttl; - for (x=0;avoid[x] && (x <DUNDI_MAX_STACK);x++) - trans->eids[x] = *avoid[x]; - trans->eidcount = x; - dr->trans = trans; - return 0; -} - -static void cancel_request(struct dundi_request *dr) -{ - struct dundi_transaction *trans, *next; - - ast_mutex_lock(&peerlock); - trans = dr->trans; - - while(trans) { - next = trans->next; - /* Orphan transaction from request */ - trans->parent = NULL; - trans->next = NULL; - /* Send final cancel */ - dundi_send(trans, DUNDI_COMMAND_CANCEL, 0, 1, NULL); - trans = next; - } - ast_mutex_unlock(&peerlock); -} - -static void abort_request(struct dundi_request *dr) -{ - ast_mutex_lock(&peerlock); - while(dr->trans) - destroy_trans(dr->trans, 0); - ast_mutex_unlock(&peerlock); -} - -static void build_transactions(struct dundi_request *dr, int ttl, int order, int *foundcache, int *skipped, int blockempty, int nocache, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int directs[]) -{ - struct dundi_peer *p; - int x; - int res; - int pass; - int allowconnect; - char eid_str[20]; - ast_mutex_lock(&peerlock); - p = peers; - while(p) { - if (modeselect == 1) { - /* Send the precache to push upstreams only! */ - pass = has_permission(p->permit, dr->dcontext) && (p->pcmodel & DUNDI_MODEL_OUTBOUND); - allowconnect = 1; - } else { - /* Normal lookup / EID query */ - pass = has_permission(p->include, dr->dcontext); - allowconnect = p->model & DUNDI_MODEL_OUTBOUND; - } - if (skip) { - if (!dundi_eid_cmp(skip, &p->eid)) - pass = 0; - } - if (pass) { - if (p->order <= order) { - /* Check order first, then check cache, regardless of - omissions, this gets us more likely to not have an - affected answer. */ - if((nocache || !(res = cache_lookup(dr, &p->eid, dr->crc32, &dr->expiration)))) { - res = 0; - /* Make sure we haven't already seen it and that it won't - affect our answer */ - for (x=0;avoid[x];x++) { - if (!dundi_eid_cmp(avoid[x], &p->eid) || !dundi_eid_cmp(avoid[x], &p->us_eid)) { - /* If not a direct connection, it affects our answer */ - if (directs && !directs[x]) - ast_clear_flag_nonstd(dr->hmd, DUNDI_HINT_UNAFFECTED); - break; - } - } - /* Make sure we can ask */ - if (allowconnect) { - if (!avoid[x] && (!blockempty || !dundi_eid_zero(&p->us_eid))) { - /* Check for a matching or 0 cache entry */ - append_transaction(dr, p, ttl, avoid); - } else - ast_log(LOG_DEBUG, "Avoiding '%s' in transaction\n", dundi_eid_to_str(eid_str, sizeof(eid_str), avoid[x])); - } - } - *foundcache |= res; - } else if (!*skipped || (p->order < *skipped)) - *skipped = p->order; - } - p = p->next; - } - ast_mutex_unlock(&peerlock); -} - -static int register_request(struct dundi_request *dr, struct dundi_request **pending) -{ - struct dundi_request *cur; - int res=0; - char eid_str[20]; - ast_mutex_lock(&peerlock); - cur = requests; - while(cur) { - if (option_debug) - ast_log(LOG_DEBUG, "Checking '%s@%s' vs '%s@%s'\n", cur->dcontext, cur->number, - dr->dcontext, dr->number); - if (!strcasecmp(cur->dcontext, dr->dcontext) && - !strcasecmp(cur->number, dr->number) && - (!dundi_eid_cmp(&cur->root_eid, &dr->root_eid) || (cur->crc32 == dr->crc32))) { - ast_log(LOG_DEBUG, "Found existing query for '%s@%s' for '%s' crc '%08lx'\n", - cur->dcontext, cur->number, dundi_eid_to_str(eid_str, sizeof(eid_str), &cur->root_eid), cur->crc32); - *pending = cur; - res = 1; - break; - } - cur = cur->next; - } - if (!res) { - ast_log(LOG_DEBUG, "Registering request for '%s@%s' on behalf of '%s' crc '%08lx'\n", - dr->number, dr->dcontext, dundi_eid_to_str(eid_str, sizeof(eid_str), &dr->root_eid), dr->crc32); - /* Go ahead and link us in since nobody else is searching for this */ - dr->next = requests; - requests = dr; - *pending = NULL; - } - ast_mutex_unlock(&peerlock); - return res; -} - -static void unregister_request(struct dundi_request *dr) -{ - struct dundi_request *cur, *prev; - ast_mutex_lock(&peerlock); - prev = NULL; - cur = requests; - while(cur) { - if (cur == dr) { - if (prev) - prev->next = cur->next; - else - requests = cur->next; - break; - } - prev = cur; - cur = cur->next; - } - ast_mutex_unlock(&peerlock); -} - -static int check_request(struct dundi_request *dr) -{ - struct dundi_request *cur; - int res = 0; - ast_mutex_lock(&peerlock); - cur = requests; - while(cur) { - if (cur == dr) { - res = 1; - break; - } - cur = cur->next; - } - ast_mutex_unlock(&peerlock); - return res; -} - -static unsigned long avoid_crc32(dundi_eid *avoid[]) -{ - /* Idea is that we're calculating a checksum which is independent of - the order that the EID's are listed in */ - unsigned long acrc32 = 0; - int x; - for (x=0;avoid[x];x++) { - /* Order doesn't matter */ - if (avoid[x+1]) { - acrc32 ^= crc32(0L, (unsigned char *)avoid[x], sizeof(dundi_eid)); - } - } - return acrc32; -} - -static int dundi_lookup_internal(struct dundi_result *result, int maxret, struct ast_channel *chan, const char *dcontext, const char *number, int ttl, int blockempty, struct dundi_hint_metadata *hmd, int *expiration, int cbypass, int modeselect, dundi_eid *skip, dundi_eid *avoid[], int direct[]) -{ - int res; - struct dundi_request dr, *pending; - dundi_eid *rooteid=NULL; - int x; - int ttlms; - int ms; - int foundcache; - int skipped=0; - int order=0; - char eid_str[20]; - struct timeval start; - - /* Don't do anthing for a hungup channel */ - if (chan && chan->_softhangup) - return 0; - - ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME; - - for (x=0;avoid[x];x++) - rooteid = avoid[x]; - /* Now perform real check */ - memset(&dr, 0, sizeof(dr)); - if (pipe(dr.pfds)) { - ast_log(LOG_WARNING, "pipe failed: %s\n" , strerror(errno)); - return -1; - } - dr.dr = result; - dr.hmd = hmd; - dr.maxcount = maxret; - dr.expiration = *expiration; - dr.cbypass = cbypass; - dr.crc32 = avoid_crc32(avoid); - ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext)); - ast_copy_string(dr.number, number, sizeof(dr.number)); - if (rooteid) - dr.root_eid = *rooteid; - res = register_request(&dr, &pending); - if (res) { - /* Already a request */ - if (rooteid && !dundi_eid_cmp(&dr.root_eid, &pending->root_eid)) { - /* This is on behalf of someone else. Go ahead and close this out since - they'll get their answer anyway. */ - ast_log(LOG_DEBUG, "Oooh, duplicate request for '%s@%s' for '%s'\n", - dr.number,dr.dcontext,dundi_eid_to_str(eid_str, sizeof(eid_str), &dr.root_eid)); - close(dr.pfds[0]); - close(dr.pfds[1]); - return -2; - } else { - /* Wait for the cache to populate */ - ast_log(LOG_DEBUG, "Waiting for similar request for '%s@%s' for '%s'\n", - dr.number,dr.dcontext,dundi_eid_to_str(eid_str, sizeof(eid_str), &pending->root_eid)); - start = ast_tvnow(); - while(check_request(pending) && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !chan->_softhangup)) { - /* XXX Would be nice to have a way to poll/select here XXX */ - /* XXX this is a busy wait loop!!! */ - usleep(1); - } - /* Continue on as normal, our cache should kick in */ - } - } - /* Create transactions */ - do { - order = skipped; - skipped = 0; - foundcache = 0; - build_transactions(&dr, ttl, order, &foundcache, &skipped, blockempty, cbypass, modeselect, skip, avoid, direct); - } while (skipped && !foundcache && !dr.trans); - /* If no TTL, abort and return 0 now after setting TTL expired hint. Couldn't - do this earlier because we didn't know if we were going to have transactions - or not. */ - if (!ttl) { - ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED); - abort_request(&dr); - unregister_request(&dr); - close(dr.pfds[0]); - close(dr.pfds[1]); - return 0; - } - - /* Optimize transactions */ - optimize_transactions(&dr, order); - /* Actually perform transactions */ - discover_transactions(&dr); - /* Wait for transaction to come back */ - start = ast_tvnow(); - while(dr.trans && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms) && (!chan || !chan->_softhangup)) { - ms = 100; - ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL); - } - if (chan && chan->_softhangup) - ast_log(LOG_DEBUG, "Hrm, '%s' hungup before their query for %s@%s finished\n", chan->name, dr.number, dr.dcontext); - cancel_request(&dr); - unregister_request(&dr); - res = dr.respcount; - *expiration = dr.expiration; - close(dr.pfds[0]); - close(dr.pfds[1]); - return res; -} - -int dundi_lookup(struct dundi_result *result, int maxret, struct ast_channel *chan, const char *dcontext, const char *number, int cbypass) -{ - struct dundi_hint_metadata hmd; - dundi_eid *avoid[1] = { NULL, }; - int direct[1] = { 0, }; - int expiration = dundi_cache_time; - memset(&hmd, 0, sizeof(hmd)); - hmd.flags = DUNDI_HINT_DONT_ASK | DUNDI_HINT_UNAFFECTED; - return dundi_lookup_internal(result, maxret, chan, dcontext, number, dundi_ttl, 0, &hmd, &expiration, cbypass, 0, NULL, avoid, direct); -} - -static void reschedule_precache(const char *number, const char *context, int expiration) -{ - int len; - struct dundi_precache_queue *qe, *prev=NULL; - ast_mutex_lock(&pclock); - qe = pcq; - while(qe) { - if (!strcmp(number, qe->number) && !strcasecmp(context, qe->context)) { - if (prev) - prev->next = qe->next; - else - pcq = qe->next; - qe->next = NULL; - break; - } - prev = qe; - qe = qe->next; - }; - if (!qe) { - len = sizeof(struct dundi_precache_queue); - len += strlen(number) + 1; - len += strlen(context) + 1; - qe = malloc(len); - if (qe) { - memset(qe, 0, len); - strcpy(qe->number, number); - qe->context = qe->number + strlen(number) + 1; - strcpy(qe->context, context); - } - } - time(&qe->expiration); - qe->expiration += expiration; - prev = pcq; - if (prev) { - while(prev->next && (prev->next->expiration <= qe->expiration)) - prev = prev->next; - qe->next = prev->next; - prev->next = qe; - } else - pcq = qe; - ast_mutex_unlock(&pclock); - -} - -static void dundi_precache_full(void) -{ - struct dundi_mapping *cur; - struct ast_context *con; - struct ast_exten *e; - cur = mappings; - while(cur) { - ast_log(LOG_NOTICE, "Should precache context '%s'\n", cur->dcontext); - ast_lock_contexts(); - con = ast_walk_contexts(NULL); - while(con) { - if (!strcasecmp(cur->lcontext, ast_get_context_name(con))) { - /* Found the match, now queue them all up */ - ast_lock_context(con); - e = ast_walk_context_extensions(con, NULL); - while(e) { - reschedule_precache(ast_get_extension_name(e), cur->dcontext, 0); - e = ast_walk_context_extensions(con, e); - } - ast_unlock_context(con); - } - con = ast_walk_contexts(con); - } - ast_unlock_contexts(); - cur = cur->next; - } -} - -static int dundi_precache_internal(const char *context, const char *number, int ttl, dundi_eid *avoids[]) -{ - struct dundi_request dr; - struct dundi_hint_metadata hmd; - struct dundi_result dr2[MAX_RESULTS]; - struct timeval start; - struct dundi_mapping *maps=NULL, *cur; - int nummaps; - int foundanswers; - int foundcache, skipped, ttlms, ms; - if (!context) - context = "e164"; - ast_log(LOG_DEBUG, "Precache internal (%s@%s)!\n", number, context); - - ast_mutex_lock(&peerlock); - nummaps = 0; - cur = mappings; - while(cur) { - if (!strcasecmp(cur->dcontext, context)) - nummaps++; - cur = cur->next; - } - if (nummaps) { - maps = alloca(nummaps * sizeof(struct dundi_mapping)); - nummaps = 0; - if (maps) { - cur = mappings; - while(cur) { - if (!strcasecmp(cur->dcontext, context)) - maps[nummaps++] = *cur; - cur = cur->next; - } - } - } - ast_mutex_unlock(&peerlock); - if (!nummaps || !maps) - return -1; - ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME; - memset(&dr2, 0, sizeof(dr2)); - memset(&dr, 0, sizeof(dr)); - memset(&hmd, 0, sizeof(hmd)); - dr.dr = dr2; - ast_copy_string(dr.number, number, sizeof(dr.number)); - ast_copy_string(dr.dcontext, context ? context : "e164", sizeof(dr.dcontext)); - dr.maxcount = MAX_RESULTS; - dr.expiration = dundi_cache_time; - dr.hmd = &hmd; - dr.pfds[0] = dr.pfds[1] = -1; - pipe(dr.pfds); - build_transactions(&dr, ttl, 0, &foundcache, &skipped, 0, 1, 1, NULL, avoids, NULL); - optimize_transactions(&dr, 0); - foundanswers = 0; - precache_transactions(&dr, maps, nummaps, &dr.expiration, &foundanswers); - if (foundanswers) { - if (dr.expiration > 0) - reschedule_precache(dr.number, dr.dcontext, dr.expiration); - else - ast_log(LOG_NOTICE, "Weird, expiration = %d, but need to precache for %s@%s?!\n", dr.expiration, dr.number, dr.dcontext); - } - start = ast_tvnow(); - while(dr.trans && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms)) { - if (dr.pfds[0] > -1) { - ms = 100; - ast_waitfor_n_fd(dr.pfds, 1, &ms, NULL); - } else - usleep(1); - } - cancel_request(&dr); - if (dr.pfds[0] > -1) { - close(dr.pfds[0]); - close(dr.pfds[1]); - } - return 0; -} - -int dundi_precache(const char *context, const char *number) -{ - dundi_eid *avoid[1] = { NULL, }; - return dundi_precache_internal(context, number, dundi_ttl, avoid); -} - -static int dundi_query_eid_internal(struct dundi_entity_info *dei, const char *dcontext, dundi_eid *eid, struct dundi_hint_metadata *hmd, int ttl, int blockempty, dundi_eid *avoid[]) -{ - int res; - struct dundi_request dr; - dundi_eid *rooteid=NULL; - int x; - int ttlms; - int skipped=0; - int foundcache=0; - struct timeval start; - - ttlms = DUNDI_FLUFF_TIME + ttl * DUNDI_TTL_TIME; - - for (x=0;avoid[x];x++) - rooteid = avoid[x]; - /* Now perform real check */ - memset(&dr, 0, sizeof(dr)); - dr.hmd = hmd; - dr.dei = dei; - dr.pfds[0] = dr.pfds[1] = -1; - ast_copy_string(dr.dcontext, dcontext ? dcontext : "e164", sizeof(dr.dcontext)); - memcpy(&dr.query_eid, eid, sizeof(dr.query_eid)); - if (rooteid) - dr.root_eid = *rooteid; - /* Create transactions */ - build_transactions(&dr, ttl, 9999, &foundcache, &skipped, blockempty, 0, 0, NULL, avoid, NULL); - - /* If no TTL, abort and return 0 now after setting TTL expired hint. Couldn't - do this earlier because we didn't know if we were going to have transactions - or not. */ - if (!ttl) { - ast_set_flag_nonstd(hmd, DUNDI_HINT_TTL_EXPIRED); - return 0; - } - - /* Optimize transactions */ - optimize_transactions(&dr, 9999); - /* Actually perform transactions */ - query_transactions(&dr); - /* Wait for transaction to come back */ - start = ast_tvnow(); - while(dr.trans && (ast_tvdiff_ms(ast_tvnow(), start) < ttlms)) - usleep(1); - res = dr.respcount; - return res; -} - -int dundi_query_eid(struct dundi_entity_info *dei, const char *dcontext, dundi_eid eid) -{ - dundi_eid *avoid[1] = { NULL, }; - struct dundi_hint_metadata hmd; - memset(&hmd, 0, sizeof(hmd)); - return dundi_query_eid_internal(dei, dcontext, &eid, &hmd, dundi_ttl, 0, avoid); -} - -/*! - * \ingroup applications - */ -static int dundi_lookup_exec(struct ast_channel *chan, void *data) -{ - char *num; - char *context; - char *opts; - int results; - int x; - int bypass = 0; - struct localuser *u; - struct dundi_result dr[MAX_RESULTS]; - static int dep_warning = 0; - - LOCAL_USER_ADD(u); - - if (!dep_warning) { - ast_log(LOG_WARNING, "This application has been deprecated in favor of the DUNDILOOKUP dialplan function.\n"); - dep_warning = 1; - } - - if (ast_strlen_zero(data)) { - ast_log(LOG_WARNING, "DUNDiLookup requires an argument (number)\n"); - LOCAL_USER_REMOVE(u); - return 0; - } - - num = ast_strdupa(data); - if (!num) { - ast_log(LOG_ERROR, "Out of memory!\n"); - LOCAL_USER_REMOVE(u); - return 0; - } - - context = strchr(num, '|'); - if (context) { - *context = '\0'; - context++; - opts = strchr(context, '|'); - if (opts) { - *opts = '\0'; - opts++; - if (strchr(opts, 'b')) - bypass = 1; - } - } - - if (ast_strlen_zero(context)) - context = "e164"; - - results = dundi_lookup(dr, MAX_RESULTS, NULL, context, num, bypass); - if (results > 0) { - sort_results(dr, results); - for (x = 0; x < results; x++) { - if (ast_test_flag(dr + x, DUNDI_FLAG_EXISTS)) { - pbx_builtin_setvar_helper(chan, "DUNDTECH", dr[x].tech); - pbx_builtin_setvar_helper(chan, "DUNDDEST", dr[x].dest); - break; - } - } - } else if (option_priority_jumping) - ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); - - LOCAL_USER_REMOVE(u); - - return 0; -} - -static char *dundifunc_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) -{ - char *num; - char *context; - char *opts; - int results; - int x; - int bypass = 0; - struct localuser *u; - struct dundi_result dr[MAX_RESULTS]; - - LOCAL_USER_ACF_ADD(u); - - buf[0] = '\0'; - - if (ast_strlen_zero(data)) { - ast_log(LOG_WARNING, "DUNDILOOKUP requires an argument (number)\n"); - LOCAL_USER_REMOVE(u); - return buf; - } - - num = ast_strdupa(data); - if (!num) { - ast_log(LOG_ERROR, "Out of memory!\n"); - LOCAL_USER_REMOVE(u); - return buf; - } - - context = strchr(num, '|'); - if (context) { - *context = '\0'; - context++; - opts = strchr(context, '|'); - if (opts) { - *opts = '\0'; - opts++; - if (strchr(opts, 'b')) - bypass = 1; - } - } - - if (ast_strlen_zero(context)) - context = "e164"; - - results = dundi_lookup(dr, MAX_RESULTS, NULL, context, num, bypass); - if (results > 0) { - sort_results(dr, results); - for (x = 0; x < results; x++) { - if (ast_test_flag(dr + x, DUNDI_FLAG_EXISTS)) { - snprintf(buf, len, "%s/%s", dr[x].tech, dr[x].dest); - break; - } - } - } - - LOCAL_USER_REMOVE(u); - - return buf; -} - -/*! DUNDILOOKUP - * \ingroup functions -*/ - -static struct ast_custom_function dundi_function = { - .name = "DUNDILOOKUP", - .synopsis = "Do a DUNDi lookup of a phone number.", - .syntax = "DUNDILOOKUP(number[|context[|options]])", - .desc = "This will do a DUNDi lookup of the given phone number.\n" - "If no context is given, the default will be e164. The result of\n" - "this function will the Technology/Resource found in the DUNDi\n" - "lookup. If no results were found, the result will be blank.\n" - "If the 'b' option is specified, the internal DUNDi cache will\n" - "be bypassed.\n", - .read = dundifunc_read, -}; - -static void mark_peers(void) -{ - struct dundi_peer *peer; - ast_mutex_lock(&peerlock); - peer = peers; - while(peer) { - peer->dead = 1; - peer = peer->next; - } - ast_mutex_unlock(&peerlock); -} - -static void mark_mappings(void) -{ - struct dundi_mapping *map; - ast_mutex_lock(&peerlock); - map = mappings; - while(map) { - map->dead = 1; - map = map->next; - } - ast_mutex_unlock(&peerlock); -} - -static void destroy_permissions(struct permission *p) -{ - struct permission *prev; - while(p) { - prev = p; - p = p->next; - free(prev); - } -} - -static void destroy_peer(struct dundi_peer *peer) -{ - if (peer->registerid > -1) - ast_sched_del(sched, peer->registerid); - if (peer->regtrans) - destroy_trans(peer->regtrans, 0); - if (peer->keypending) - destroy_trans(peer->keypending, 0); - if (peer->qualifyid > -1) - ast_sched_del(sched, peer->qualifyid); - destroy_permissions(peer->permit); - destroy_permissions(peer->include); - free(peer); -} - -static void destroy_map(struct dundi_mapping *map) -{ - free(map); -} - -static void prune_peers(void) -{ - struct dundi_peer *peer, *prev, *next; - ast_mutex_lock(&peerlock); - peer = peers; - prev = NULL; - while(peer) { - next = peer->next; - if (peer->dead) { - if (prev) - prev->next = peer->next; - else - peers = peer->next; - destroy_peer(peer); - } else - prev = peer; - peer = next; - } - ast_mutex_unlock(&peerlock); -} - -static void prune_mappings(void) -{ - struct dundi_mapping *map, *prev, *next; - ast_mutex_lock(&peerlock); - map = mappings; - prev = NULL; - while(map) { - next = map->next; - if (map->dead) { - if (prev) - prev->next = map->next; - else - mappings = map->next; - destroy_map(map); - } else - prev = map; - map = next; - } - ast_mutex_unlock(&peerlock); -} - -static struct permission *append_permission(struct permission *p, char *s, int allow) -{ - struct permission *start; - start = p; - if (p) { - while(p->next) - p = p->next; - } - if (p) { - p->next = malloc(sizeof(struct permission) + strlen(s) + 1); - p = p->next; - } else { - p = malloc(sizeof(struct permission) + strlen(s) + 1); - } - if (p) { - memset(p, 0, sizeof(struct permission)); - memcpy(p->name, s, strlen(s) + 1); - p->allow = allow; - } - return start ? start : p; -} - -#define MAX_OPTS 128 - -static void build_mapping(char *name, char *value) -{ - char *t, *fields[MAX_OPTS]; - struct dundi_mapping *map; - int x; - int y; - t = ast_strdupa(value); - if (t) { - map = mappings; - while(map) { - /* Find a double match */ - if (!strcasecmp(map->dcontext, name) && - (!strncasecmp(map->lcontext, value, strlen(map->lcontext)) && - (!value[strlen(map->lcontext)] || - (value[strlen(map->lcontext)] == ',')))) - break; - map = map->next; - } - if (!map) { - map = malloc(sizeof(struct dundi_mapping)); - if (map) { - memset(map, 0, sizeof(struct dundi_mapping)); - map->next = mappings; - mappings = map; - map->dead = 1; - } - } - if (map) { - map->options = 0; - memset(fields, 0, sizeof(fields)); - x = 0; - while(t && x < MAX_OPTS) { - fields[x++] = t; - t = strchr(t, ','); - if (t) { - *t = '\0'; - t++; - } - } /* Russell was here, arrrr! */ - if ((x == 1) && ast_strlen_zero(fields[0])) { - /* Placeholder mapping */ - ast_copy_string(map->dcontext, name, sizeof(map->dcontext)); - map->dead = 0; - } else if (x >= 4) { - ast_copy_string(map->dcontext, name, sizeof(map->dcontext)); - ast_copy_string(map->lcontext, fields[0], sizeof(map->lcontext)); - if ((sscanf(fields[1], "%d", &map->weight) == 1) && (map->weight >= 0) && (map->weight < 60000)) { - ast_copy_string(map->dest, fields[3], sizeof(map->dest)); - if ((map->tech = str2tech(fields[2]))) { - map->dead = 0; - } - } else { - ast_log(LOG_WARNING, "Invalid weight '%s' specified, deleting entry '%s/%s'\n", fields[1], map->dcontext, map->lcontext); - } - for (y=4;y<x;y++) { - if (!strcasecmp(fields[y], "nounsolicited")) - map->options |= DUNDI_FLAG_NOUNSOLICITED; - else if (!strcasecmp(fields[y], "nocomunsolicit")) - map->options |= DUNDI_FLAG_NOCOMUNSOLICIT; - else if (!strcasecmp(fields[y], "residential")) - map->options |= DUNDI_FLAG_RESIDENTIAL; - else if (!strcasecmp(fields[y], "commercial")) - map->options |= DUNDI_FLAG_COMMERCIAL; - else if (!strcasecmp(fields[y], "mobile")) - map->options |= DUNDI_FLAG_MOBILE; - else if (!strcasecmp(fields[y], "nopartial")) - map->options |= DUNDI_FLAG_INTERNAL_NOPARTIAL; - else - ast_log(LOG_WARNING, "Don't know anything about option '%s'\n", fields[y]); - } - } else - ast_log(LOG_WARNING, "Expected at least %d arguments in map, but got only %d\n", 4, x); - } - } -} - -static int do_register(void *data) -{ - struct dundi_ie_data ied; - struct dundi_peer *peer = data; - char eid_str[20]; - char eid_str2[20]; - /* Called with peerlock already held */ - ast_log(LOG_DEBUG, "Register us as '%s' to '%s'\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->us_eid), dundi_eid_to_str(eid_str2, sizeof(eid_str2), &peer->eid)); - peer->registerid = ast_sched_add(sched, default_expiration * 1000, do_register, data); - /* Destroy old transaction if there is one */ - if (peer->regtrans) - destroy_trans(peer->regtrans, 0); - peer->regtrans = create_transaction(peer); - if (peer->regtrans) { - ast_set_flag(peer->regtrans, FLAG_ISREG); - memset(&ied, 0, sizeof(ied)); - dundi_ie_append_short(&ied, DUNDI_IE_VERSION, DUNDI_DEFAULT_VERSION); - dundi_ie_append_eid(&ied, DUNDI_IE_EID, &peer->regtrans->us_eid); - dundi_ie_append_short(&ied, DUNDI_IE_EXPIRATION, default_expiration); - dundi_send(peer->regtrans, DUNDI_COMMAND_REGREQ, 0, 0, &ied); - - } else - ast_log(LOG_NOTICE, "Unable to create new transaction for registering to '%s'!\n", dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); - - return 0; -} - -static int do_qualify(void *data) -{ - struct dundi_peer *peer; - peer = data; - peer->qualifyid = -1; - qualify_peer(peer, 0); - return 0; -} - -static void qualify_peer(struct dundi_peer *peer, int schedonly) -{ - int when; - if (peer->qualifyid > -1) - ast_sched_del(sched, peer->qualifyid); - peer->qualifyid = -1; - if (peer->qualtrans) - destroy_trans(peer->qualtrans, 0); - peer->qualtrans = NULL; - if (peer->maxms > 0) { - when = 60000; - if (peer->lastms < 0) - when = 10000; - if (schedonly) - when = 5000; - peer->qualifyid = ast_sched_add(sched, when, do_qualify, peer); - if (!schedonly) - peer->qualtrans = create_transaction(peer); - if (peer->qualtrans) { - peer->qualtx = ast_tvnow(); - ast_set_flag(peer->qualtrans, FLAG_ISQUAL); - dundi_send(peer->qualtrans, DUNDI_COMMAND_NULL, 0, 1, NULL); - } - } -} -static void populate_addr(struct dundi_peer *peer, dundi_eid *eid) -{ - char data[256]; - char *c; - int port, expire; - char eid_str[20]; - dundi_eid_to_str(eid_str, sizeof(eid_str), eid); - if (!ast_db_get("dundi/dpeers", eid_str, data, sizeof(data))) { - c = strchr(data, ':'); - if (c) { - *c = '\0'; - c++; - if (sscanf(c, "%d:%d", &port, &expire) == 2) { - /* Got it! */ - inet_aton(data, &peer->addr.sin_addr); - peer->addr.sin_family = AF_INET; - peer->addr.sin_port = htons(port); - peer->registerexpire = ast_sched_add(sched, (expire + 10) * 1000, do_register_expire, peer); - } - } - } -} - - -static void build_peer(dundi_eid *eid, struct ast_variable *v, int *globalpcmode) -{ - struct dundi_peer *peer; - struct ast_hostent he; - struct hostent *hp; - dundi_eid testeid; - int needregister=0; - char eid_str[20]; - - ast_mutex_lock(&peerlock); - peer = peers; - while(peer) { - if (!dundi_eid_cmp(&peer->eid, eid)) { - break; - } - peer = peer->next; - } - if (!peer) { - /* Add us into the list */ - peer = malloc(sizeof(struct dundi_peer)); - if (peer) { - memset(peer, 0, sizeof(struct dundi_peer)); - peer->registerid = -1; - peer->registerexpire = -1; - peer->qualifyid = -1; - peer->addr.sin_family = AF_INET; - peer->addr.sin_port = htons(DUNDI_PORT); - populate_addr(peer, eid); - peer->next = peers; - peers = peer; - } - } - if (peer) { - peer->dead = 0; - peer->eid = *eid; - peer->us_eid = global_eid; - destroy_permissions(peer->permit); - destroy_permissions(peer->include); - peer->permit = NULL; - peer->include = NULL; - if (peer->registerid > -1) - ast_sched_del(sched, peer->registerid); - peer->registerid = -1; - while(v) { - if (!strcasecmp(v->name, "inkey")) { - ast_copy_string(peer->inkey, v->value, sizeof(peer->inkey)); - } else if (!strcasecmp(v->name, "outkey")) { - ast_copy_string(peer->outkey, v->value, sizeof(peer->outkey)); - } else if (!strcasecmp(v->name, "host")) { - if (!strcasecmp(v->value, "dynamic")) { - peer->dynamic = 1; - } else { - hp = ast_gethostbyname(v->value, &he); - if (hp) { - memcpy(&peer->addr.sin_addr, hp->h_addr, sizeof(peer->addr.sin_addr)); - peer->dynamic = 0; - } else { - ast_log(LOG_WARNING, "Unable to find host '%s' at line %d\n", v->value, v->lineno); - peer->dead = 1; - } - } - } else if (!strcasecmp(v->name, "ustothem")) { - if (!dundi_str_to_eid(&testeid, v->value)) - peer->us_eid = testeid; - else - ast_log(LOG_WARNING, "'%s' is not a valid DUNDi Entity Identifier at line %d\n", v->value, v->lineno); - } else if (!strcasecmp(v->name, "include")) { - peer->include = append_permission(peer->include, v->value, 1); - } else if (!strcasecmp(v->name, "permit")) { - peer->permit = append_permission(peer->permit, v->value, 1); - } else if (!strcasecmp(v->name, "noinclude")) { - peer->include = append_permission(peer->include, v->value, 0); - } else if (!strcasecmp(v->name, "deny")) { - peer->permit = append_permission(peer->permit, v->value, 0); - } else if (!strcasecmp(v->name, "register")) { - needregister = ast_true(v->value); - } else if (!strcasecmp(v->name, "order")) { - if (!strcasecmp(v->value, "primary")) - peer->order = 0; - else if (!strcasecmp(v->value, "secondary")) - peer->order = 1; - else if (!strcasecmp(v->value, "tertiary")) - peer->order = 2; - else if (!strcasecmp(v->value, "quartiary")) - peer->order = 3; - else { - ast_log(LOG_WARNING, "'%s' is not a valid order, should be primary, secondary, tertiary or quartiary at line %d\n", v->value, v->lineno); - } - } else if (!strcasecmp(v->name, "qualify")) { - if (!strcasecmp(v->value, "no")) { - peer->maxms = 0; - } else if (!strcasecmp(v->value, "yes")) { - peer->maxms = DEFAULT_MAXMS; - } else if (sscanf(v->value, "%d", &peer->maxms) != 1) { - ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of dundi.conf\n", - dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid), v->lineno); - peer->maxms = 0; - } - } else if (!strcasecmp(v->name, "model")) { - if (!strcasecmp(v->value, "inbound")) - peer->model = DUNDI_MODEL_INBOUND; - else if (!strcasecmp(v->value, "outbound")) - peer->model = DUNDI_MODEL_OUTBOUND; - else if (!strcasecmp(v->value, "symmetric")) - peer->model = DUNDI_MODEL_SYMMETRIC; - else if (!strcasecmp(v->value, "none")) - peer->model = 0; - else { - ast_log(LOG_WARNING, "Unknown model '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", - v->value, v->lineno); - } - } else if (!strcasecmp(v->name, "precache")) { - if (!strcasecmp(v->value, "inbound")) - peer->pcmodel = DUNDI_MODEL_INBOUND; - else if (!strcasecmp(v->value, "outbound")) - peer->pcmodel = DUNDI_MODEL_OUTBOUND; - else if (!strcasecmp(v->value, "symmetric")) - peer->pcmodel = DUNDI_MODEL_SYMMETRIC; - else if (!strcasecmp(v->value, "none")) - peer->pcmodel = 0; - else { - ast_log(LOG_WARNING, "Unknown pcmodel '%s', should be 'none', 'outbound', 'inbound', or 'symmetric' at line %d\n", - v->value, v->lineno); - } - } - v = v->next; - } - (*globalpcmode) |= peer->pcmodel; - if (!peer->model && !peer->pcmodel) { - ast_log(LOG_WARNING, "Peer '%s' lacks a model or pcmodel, discarding!\n", - dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); - peer->dead = 1; - } else if ((peer->model & DUNDI_MODEL_INBOUND) && (peer->pcmodel & DUNDI_MODEL_OUTBOUND)) { - ast_log(LOG_WARNING, "Peer '%s' may not be both inbound/symmetric model and outbound/symmetric precache model, discarding!\n", - dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); - peer->dead = 1; - } else if ((peer->model & DUNDI_MODEL_OUTBOUND) && (peer->pcmodel & DUNDI_MODEL_INBOUND)) { - ast_log(LOG_WARNING, "Peer '%s' may not be both outbound/symmetric model and inbound/symmetric precache model, discarding!\n", - dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); - peer->dead = 1; - } else if (peer->include && !(peer->model & DUNDI_MODEL_OUTBOUND) && !(peer->pcmodel & DUNDI_MODEL_INBOUND)) { - ast_log(LOG_WARNING, "Peer '%s' is supposed to be included in outbound searches but isn't an outbound peer or inbound precache!\n", - dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); - } else if (peer->permit && !(peer->model & DUNDI_MODEL_INBOUND) && !(peer->pcmodel & DUNDI_MODEL_OUTBOUND)) { - ast_log(LOG_WARNING, "Peer '%s' is supposed to have permission for some inbound searches but isn't an inbound peer or outbound precache!\n", - dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid)); - } else { - if (needregister) { - peer->registerid = ast_sched_add(sched, 2000, do_register, peer); - } - qualify_peer(peer, 1); - } - } - ast_mutex_unlock(&peerlock); -} - -static int dundi_helper(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *data, int flag) -{ - struct dundi_result results[MAX_RESULTS]; - int res; - int x; - int found = 0; - if (!strncasecmp(context, "macro-", 6)) { - if (!chan) { - ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n"); - return -1; - } - /* If done as a macro, use macro extension */ - if (!strcasecmp(exten, "s")) { - exten = pbx_builtin_getvar_helper(chan, "ARG1"); - if (ast_strlen_zero(exten)) - exten = chan->macroexten; - if (ast_strlen_zero(exten)) - exten = chan->exten; - if (ast_strlen_zero(exten)) { - ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n"); - return -1; - } - } - if (ast_strlen_zero(data)) - data = "e164"; - } else { - if (ast_strlen_zero(data)) - data = context; - } - res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0); - for (x=0;x<res;x++) { - if (ast_test_flag(results + x, flag)) - found++; - } - if (found >= priority) - return 1; - return 0; -} - -static int dundi_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) -{ - return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_EXISTS); -} - -static int dundi_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) -{ - return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_CANMATCH); -} - -static int dundi_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, int newstack, const char *data) -{ - struct dundi_result results[MAX_RESULTS]; - int res; - int x=0; - char req[1024]; - struct ast_app *dial; - - if (!strncasecmp(context, "macro-", 6)) { - if (!chan) { - ast_log(LOG_NOTICE, "Can't use macro mode without a channel!\n"); - return -1; - } - /* If done as a macro, use macro extension */ - if (!strcasecmp(exten, "s")) { - exten = pbx_builtin_getvar_helper(chan, "ARG1"); - if (ast_strlen_zero(exten)) - exten = chan->macroexten; - if (ast_strlen_zero(exten)) - exten = chan->exten; - if (ast_strlen_zero(exten)) { - ast_log(LOG_WARNING, "Called in Macro mode with no ARG1 or MACRO_EXTEN?\n"); - return -1; - } - } - if (ast_strlen_zero(data)) - data = "e164"; - } else { - if (ast_strlen_zero(data)) - data = context; - } - res = dundi_lookup(results, MAX_RESULTS, chan, data, exten, 0); - if (res > 0) { - sort_results(results, res); - for (x=0;x<res;x++) { - if (ast_test_flag(results + x, DUNDI_FLAG_EXISTS)) { - if (!--priority) - break; - } - } - } - if (x < res) { - /* Got a hit! */ - snprintf(req, sizeof(req), "%s/%s", results[x].tech, results[x].dest); - dial = pbx_findapp("Dial"); - if (dial) - res = pbx_exec(chan, dial, req, newstack); - } else - res = -1; - return res; -} - -static int dundi_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) -{ - return dundi_helper(chan, context, exten, priority, data, DUNDI_FLAG_MATCHMORE); -} - -static struct ast_switch dundi_switch = -{ - name: "DUNDi", - description: "DUNDi Discovered Dialplan Switch", - exists: dundi_exists, - canmatch: dundi_canmatch, - exec: dundi_exec, - matchmore: dundi_matchmore, -}; - -static int set_config(char *config_file, struct sockaddr_in* sin) -{ - struct ast_config *cfg; - struct ast_variable *v; - char *cat; - int format; - int x; - char hn[MAXHOSTNAMELEN] = ""; - struct ast_hostent he; - struct hostent *hp; - struct sockaddr_in sin2; - static int last_port = 0; - int globalpcmodel = 0; - dundi_eid testeid; - - dundi_ttl = DUNDI_DEFAULT_TTL; - dundi_cache_time = DUNDI_DEFAULT_CACHE_TIME; - cfg = ast_config_load(config_file); - - - if (!cfg) { - ast_log(LOG_ERROR, "Unable to load config %s\n", config_file); - return -1; - } - ipaddr[0] = '\0'; - if (!gethostname(hn, sizeof(hn)-1)) { - hp = ast_gethostbyname(hn, &he); - if (hp) { - memcpy(&sin2.sin_addr, hp->h_addr, sizeof(sin2.sin_addr)); - ast_inet_ntoa(ipaddr, sizeof(ipaddr), sin2.sin_addr); - } else - ast_log(LOG_WARNING, "Unable to look up host '%s'\n", hn); - } else - ast_log(LOG_WARNING, "Unable to get host name!\n"); - ast_mutex_lock(&peerlock); - reset_global_eid(); - global_storehistory = 0; - ast_copy_string(secretpath, "dundi", sizeof(secretpath)); - v = ast_variable_browse(cfg, "general"); - while(v) { - if (!strcasecmp(v->name, "port")){ - sin->sin_port = ntohs(atoi(v->value)); - if(last_port==0){ - last_port=sin->sin_port; - } else if(sin->sin_port != last_port) - ast_log(LOG_WARNING, "change to port ignored until next asterisk re-start\n"); - } else if (!strcasecmp(v->name, "bindaddr")) { - struct hostent *hp; - struct ast_hostent he; - hp = ast_gethostbyname(v->value, &he); - if (hp) { - memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr)); - } else - ast_log(LOG_WARNING, "Invalid host/IP '%s'\n", v->value); - } else if (!strcasecmp(v->name, "authdebug")) { - authdebug = ast_true(v->value); - } else if (!strcasecmp(v->name, "ttl")) { - if ((sscanf(v->value, "%d", &x) == 1) && (x > 0) && (x < DUNDI_DEFAULT_TTL)) { - dundi_ttl = x; - } else { - ast_log(LOG_WARNING, "'%s' is not a valid TTL at line %d, must be number from 1 to %d\n", - v->value, v->lineno, DUNDI_DEFAULT_TTL); - } - } else if (!strcasecmp(v->name, "autokill")) { - if (sscanf(v->value, "%d", &x) == 1) { - if (x >= 0) - global_autokilltimeout = x; - else - ast_log(LOG_NOTICE, "Nice try, but autokill has to be >0 or 'yes' or 'no' at line %d\n", v->lineno); - } else if (ast_true(v->value)) { - global_autokilltimeout = DEFAULT_MAXMS; - } else { - global_autokilltimeout = 0; - } - } else if (!strcasecmp(v->name, "entityid")) { - if (!dundi_str_to_eid(&testeid, v->value)) - global_eid = testeid; - else - ast_log(LOG_WARNING, "Invalid global endpoint identifier '%s' at line %d\n", v->value, v->lineno); - } else if (!strcasecmp(v->name, "tos")) { - if (sscanf(v->value, "%d", &format) == 1) - tos = format & 0xff; - else if (!strcasecmp(v->value, "lowdelay")) - tos = IPTOS_LOWDELAY; - else if (!strcasecmp(v->value, "throughput")) - tos = IPTOS_THROUGHPUT; - else if (!strcasecmp(v->value, "reliability")) - tos = IPTOS_RELIABILITY; -#if !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(SOLARIS) - else if (!strcasecmp(v->value, "mincost")) - tos = IPTOS_MINCOST; -#endif - else if (!strcasecmp(v->value, "none")) - tos = 0; - else -#if !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(SOLARIS) - ast_log(LOG_WARNING, "Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', 'mincost', or 'none'\n", v->lineno); -#else - ast_log(LOG_WARNING, "Invalid tos value at line %d, should be 'lowdelay', 'throughput', 'reliability', or 'none'\n", v->lineno); -#endif - } else if (!strcasecmp(v->name, "department")) { - ast_copy_string(dept, v->value, sizeof(dept)); - } else if (!strcasecmp(v->name, "organization")) { - ast_copy_string(org, v->value, sizeof(org)); - } else if (!strcasecmp(v->name, "locality")) { - ast_copy_string(locality, v->value, sizeof(locality)); - } else if (!strcasecmp(v->name, "stateprov")) { - ast_copy_string(stateprov, v->value, sizeof(stateprov)); - } else if (!strcasecmp(v->name, "country")) { - ast_copy_string(country, v->value, sizeof(country)); - } else if (!strcasecmp(v->name, "email")) { - ast_copy_string(email, v->value, sizeof(email)); - } else if (!strcasecmp(v->name, "phone")) { - ast_copy_string(phone, v->value, sizeof(phone)); - } else if (!strcasecmp(v->name, "storehistory")) { - global_storehistory = ast_true(v->value); - } else if (!strcasecmp(v->name, "cachetime")) { - if ((sscanf(v->value, "%d", &x) == 1)) { - dundi_cache_time = x; - } else { - ast_log(LOG_WARNING, "'%s' is not a valid cache time at line %d. Using default value '%d'.\n", - v->value, v->lineno, DUNDI_DEFAULT_CACHE_TIME); - } - } - v = v->next; - } - ast_mutex_unlock(&peerlock); - mark_mappings(); - v = ast_variable_browse(cfg, "mappings"); - while(v) { - build_mapping(v->name, v->value); - v = v->next; - } - prune_mappings(); - mark_peers(); - cat = ast_category_browse(cfg, NULL); - while(cat) { - if (strcasecmp(cat, "general") && strcasecmp(cat, "mappings")) { - /* Entries */ - if (!dundi_str_to_eid(&testeid, cat)) - build_peer(&testeid, ast_variable_browse(cfg, cat), &globalpcmodel); - else - ast_log(LOG_NOTICE, "Ignoring invalid EID entry '%s'\n", cat); - } - cat = ast_category_browse(cfg, cat); - } - prune_peers(); - ast_config_destroy(cfg); - load_password(); - if (globalpcmodel & DUNDI_MODEL_OUTBOUND) - dundi_precache_full(); - return 0; -} - -int unload_module(void) -{ - int res; - STANDARD_HANGUP_LOCALUSERS; - ast_cli_unregister(&cli_debug); - ast_cli_unregister(&cli_store_history); - ast_cli_unregister(&cli_flush); - ast_cli_unregister(&cli_no_debug); - ast_cli_unregister(&cli_no_store_history); - ast_cli_unregister(&cli_show_peers); - ast_cli_unregister(&cli_show_entityid); - ast_cli_unregister(&cli_show_trans); - ast_cli_unregister(&cli_show_requests); - ast_cli_unregister(&cli_show_mappings); - ast_cli_unregister(&cli_show_precache); - ast_cli_unregister(&cli_show_peer); - ast_cli_unregister(&cli_lookup); - ast_cli_unregister(&cli_precache); - ast_cli_unregister(&cli_queryeid); - ast_unregister_switch(&dundi_switch); - ast_custom_function_unregister(&dundi_function); - res = ast_unregister_application(app); - sched_context_destroy(sched); - return res; -} - -int reload(void) -{ - struct sockaddr_in sin; - set_config("dundi.conf",&sin); - return 0; -} - -int load_module(void) -{ - int res = 0; - struct sockaddr_in sin; - char iabuf[INET_ADDRSTRLEN]; - - dundi_set_output(dundi_debug_output); - dundi_set_error(dundi_error_output); - - sin.sin_family = AF_INET; - sin.sin_port = ntohs(DUNDI_PORT); - sin.sin_addr.s_addr = INADDR_ANY; - - /* Make a UDP socket */ - io = io_context_create(); - sched = sched_context_create(); - - if (!io || !sched) { - ast_log(LOG_ERROR, "Out of memory\n"); - return -1; - } - - set_config("dundi.conf",&sin); - - netsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); - - if (netsocket < 0) { - ast_log(LOG_ERROR, "Unable to create network socket: %s\n", strerror(errno)); - return -1; - } - if (bind(netsocket,(struct sockaddr *)&sin, sizeof(sin))) { - ast_log(LOG_ERROR, "Unable to bind to %s port %d: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port), strerror(errno)); - return -1; - } - - if (option_verbose > 1) - ast_verbose(VERBOSE_PREFIX_2 "Using TOS bits %d\n", tos); - - if (setsockopt(netsocket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos))) - ast_log(LOG_WARNING, "Unable to set TOS to %d\n", tos); - - res = start_network_thread(); - if (res) { - ast_log(LOG_ERROR, "Unable to start network thread\n"); - close(netsocket); - return -1; - } - - if (option_verbose > 1) - ast_verbose(VERBOSE_PREFIX_2 "DUNDi Ready and Listening on %s port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port)); - - ast_cli_register(&cli_debug); - ast_cli_register(&cli_store_history); - ast_cli_register(&cli_flush); - ast_cli_register(&cli_no_debug); - ast_cli_register(&cli_no_store_history); - ast_cli_register(&cli_show_peers); - ast_cli_register(&cli_show_entityid); - ast_cli_register(&cli_show_trans); - ast_cli_register(&cli_show_requests); - ast_cli_register(&cli_show_mappings); - ast_cli_register(&cli_show_precache); - ast_cli_register(&cli_show_peer); - ast_cli_register(&cli_lookup); - ast_cli_register(&cli_precache); - ast_cli_register(&cli_queryeid); - if (ast_register_switch(&dundi_switch)) - ast_log(LOG_ERROR, "Unable to register DUNDi switch\n"); - ast_register_application(app, dundi_lookup_exec, synopsis, descrip); - ast_custom_function_register(&dundi_function); - - return res; -} - -char *description(void) -{ - return tdesc; -} - -int usecount(void) -{ - int res; - /* XXX DUNDi cannot be unloaded XXX */ - return 1; - STANDARD_USECOUNT(res); - return res; -} - -char *key() -{ - return ASTERISK_GPL_KEY; -} diff --git a/1.2-netsec/pbx/pbx_gtkconsole.c b/1.2-netsec/pbx/pbx_gtkconsole.c deleted file mode 100644 index f0d118b89..000000000 --- a/1.2-netsec/pbx/pbx_gtkconsole.c +++ /dev/null @@ -1,518 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief GTK Console monitor -- very kludgy right now - * - */ - -/* - * I know this might seem somewhat pointless in its current phase, but one - * of the most important parts of this module is demonstrate that modules - * can require other external libraries and still be loaded (in this - * case, a host of libraries involving gtk), so long as they are properly - * linked (see the Makefile) - */ - -#include <sys/types.h> -#include <stdlib.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <signal.h> -#include <sys/time.h> - -#include <gtk/gtk.h> -#include <glib.h> - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/pbx.h" -#include "asterisk/config.h" -#include "asterisk/module.h" -#include "asterisk/logger.h" -#include "asterisk/options.h" -#include "asterisk/cli.h" -#include "asterisk/utils.h" - -AST_MUTEX_DEFINE_STATIC(verb_lock); - -static pthread_t console_thread; - -static int inuse=0; -static int clipipe[2]; -static int cleanupid = -1; - -static char *dtext = "Asterisk PBX Console (GTK Version)"; - -static GtkWidget *window; -static GtkWidget *quit; -static GtkWidget *closew; -static GtkWidget *verb; -static GtkWidget *modules; -static GtkWidget *statusbar; -static GtkWidget *cli; - -static struct timeval last; - -static void update_statusbar(char *msg) -{ - gtk_statusbar_pop(GTK_STATUSBAR(statusbar), 1); - gtk_statusbar_push(GTK_STATUSBAR(statusbar), 1, msg); -} - -int unload_module(void) -{ - if (inuse) { - /* Kill off the main thread */ - pthread_cancel(console_thread); - gdk_threads_enter(); - gtk_widget_destroy(window); - gdk_threads_leave(); - close(clipipe[0]); - close(clipipe[1]); - } - return 0; -} - -static int cleanup(void *useless) -{ - gdk_threads_enter(); - gtk_clist_thaw(GTK_CLIST(verb)); - gtk_widget_queue_resize(verb->parent); - gtk_clist_moveto(GTK_CLIST(verb), GTK_CLIST(verb)->rows - 1, 0, 0, 0); - cleanupid = -1; - gdk_threads_leave(); - return 0; -} - - -static void __verboser(const char *stuff, int opos, int replacelast, int complete) -{ - char *s2[2]; - struct timeval tv; - int ms; - s2[0] = (char *)stuff; - s2[1] = NULL; - gtk_clist_freeze(GTK_CLIST(verb)); - if (replacelast) - gtk_clist_remove(GTK_CLIST(verb), GTK_CLIST(verb)->rows - 1); - gtk_clist_append(GTK_CLIST(verb), s2); - if (!ast_tvzero(last)) { - gdk_threads_leave(); - gettimeofday(&tv, NULL); - if (cleanupid > -1) - gtk_timeout_remove(cleanupid); - ms = ast_tvdiff_ms(tv, last); - if (ms < 100) { - /* We just got a message within 100ms, so just schedule an update - in the near future */ - cleanupid = gtk_timeout_add(200, cleanup, NULL); - } else { - cleanup(&cleanupid); - } - last = tv; - } else { - gettimeofday(&last, NULL); - } -} - -static void verboser(const char *stuff, int opos, int replacelast, int complete) -{ - ast_mutex_lock(&verb_lock); - /* Lock appropriately if we're really being called in verbose mode */ - __verboser(stuff, opos, replacelast, complete); - ast_mutex_unlock(&verb_lock); -} - -static void cliinput(void *data, int source, GdkInputCondition ic) -{ - static char buf[256]; - static int offset = 0; - int res; - char *c; - char *l; - char n; - /* Read as much stuff is there */ - res = read(source, buf + offset, sizeof(buf) - 1 - offset); - if (res > -1) - buf[res + offset] = '\0'; - /* make sure we've null terminated whatever we have so far */ - c = buf; - l = buf; - while(*c) { - if (*c == '\n') { - /* Keep the trailing \n */ - c++; - n = *c; - *c = '\0'; - __verboser(l, 0, 0, 1); - *(c - 1) = '\0'; - *c = n; - l = c; - } else - c++; - } - if (strlen(l)) { - /* We have some left over */ - memmove(buf, l, strlen(l) + 1); - offset = strlen(buf); - } else { - offset = 0; - } - -} - - -static void remove_module(void) -{ - int res; - char *module; - char buf[256]; - if (GTK_CLIST(modules)->selection) { - module= (char *)gtk_clist_get_row_data(GTK_CLIST(modules), (int) GTK_CLIST(modules)->selection->data); - gdk_threads_leave(); - res = ast_unload_resource(module, 0); - gdk_threads_enter(); - if (res) { - snprintf(buf, sizeof(buf), "Module '%s' is in use", module); - update_statusbar(buf); - } else { - snprintf(buf, sizeof(buf), "Module '%s' removed", module); - update_statusbar(buf); - } - } -} -static void reload_module(void) -{ - int res, x; - char *module; - char buf[256]; - if (GTK_CLIST(modules)->selection) { - module= (char *)gtk_clist_get_row_data(GTK_CLIST(modules), (int) GTK_CLIST(modules)->selection->data); - module = strdup(module); - if (module) { - gdk_threads_leave(); - res = ast_unload_resource(module, 0); - gdk_threads_enter(); - if (res) { - snprintf(buf, sizeof(buf), "Module '%s' is in use", module); - update_statusbar(buf); - } else { - gdk_threads_leave(); - res = ast_load_resource(module); - gdk_threads_enter(); - if (res) { - snprintf(buf, sizeof(buf), "Error reloading module '%s'", module); - } else { - snprintf(buf, sizeof(buf), "Module '%s' reloaded", module); - } - for (x=0; x < GTK_CLIST(modules)->rows; x++) { - if (!strcmp((char *)gtk_clist_get_row_data(GTK_CLIST(modules), x), module)) { - gtk_clist_select_row(GTK_CLIST(modules), x, -1); - break; - } - } - update_statusbar(buf); - - } - free(module); - } - } -} - -static void file_ok_sel(GtkWidget *w, GtkFileSelection *fs) -{ - char tmp[AST_CONFIG_MAX_PATH]; - char *module = gtk_file_selection_get_filename(fs); - char buf[256]; - snprintf(tmp, sizeof(tmp), "%s/", ast_config_AST_MODULE_DIR); - if (!strncmp(module, (char *)tmp, strlen(tmp))) - module += strlen(tmp); - gdk_threads_leave(); - if (ast_load_resource(module)) { - snprintf(buf, sizeof(buf), "Error loading module '%s'.", module); - update_statusbar(buf); - } else { - snprintf(buf, sizeof(buf), "Module '%s' loaded", module); - update_statusbar(buf); - } - gdk_threads_enter(); - gtk_widget_destroy(GTK_WIDGET(fs)); -} - -static void add_module(void) -{ - char tmp[AST_CONFIG_MAX_PATH]; - GtkWidget *filew; - snprintf(tmp, sizeof(tmp), "%s/*.so", ast_config_AST_MODULE_DIR); - filew = gtk_file_selection_new("Load Module"); - gtk_signal_connect(GTK_OBJECT (GTK_FILE_SELECTION(filew)->ok_button), - "clicked", GTK_SIGNAL_FUNC(file_ok_sel), filew); - gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION(filew)->cancel_button), - "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(filew)); - gtk_file_selection_set_filename(GTK_FILE_SELECTION(filew), (char *)tmp); - gtk_widget_show(filew); -} - -static int add_mod(const char *module, const char *description, int usecount, const char *like) -{ - char use[10]; - char *pass[4]; - int row; - snprintf(use, sizeof(use), "%d", usecount); - pass[0] = module; - pass[1] = description; - pass[2] = use; - pass[3] = NULL; - row = gtk_clist_append(GTK_CLIST(modules), pass); - gtk_clist_set_row_data(GTK_CLIST(modules), row, module); - return 0; -} - -static int mod_update(void) -{ - char *module= NULL; - /* Update the mod stuff */ - if (GTK_CLIST(modules)->selection) { - module= (char *)gtk_clist_get_row_data(GTK_CLIST(modules), (int) GTK_CLIST(modules)->selection->data); - } - gtk_clist_freeze(GTK_CLIST(modules)); - gtk_clist_clear(GTK_CLIST(modules)); - ast_update_module_list(add_mod, NULL); - if (module) - gtk_clist_select_row(GTK_CLIST(modules), gtk_clist_find_row_from_data(GTK_CLIST(modules), module), -1); - gtk_clist_thaw(GTK_CLIST(modules)); - return 1; -} - -static void exit_now(GtkWidget *widget, gpointer data) -{ - ast_loader_unregister(mod_update); - gtk_main_quit(); - inuse--; - ast_update_use_count(); - ast_unregister_verbose(verboser); - ast_unload_resource("pbx_gtkconsole", 0); - if (option_verbose > 1) - ast_verbose(VERBOSE_PREFIX_2 "GTK Console Monitor Exiting\n"); - /* XXX Trying to quit after calling this makes asterisk segfault XXX */ -} - -static void exit_completely(GtkWidget *widget, gpointer data) -{ -#if 0 - /* Clever... */ - ast_cli_command(clipipe[1], "quit"); -#else - kill(getpid(), SIGTERM); -#endif -} - -static void exit_nicely(GtkWidget *widget, gpointer data) -{ - fflush(stdout); - gtk_widget_destroy(window); -} - -static void *consolethread(void *data) -{ - gtk_widget_show(window); - gdk_threads_enter(); - gtk_main(); - gdk_threads_leave(); - return NULL; -} - -static int cli_activate(void) -{ - char buf[256] = ""; - strncpy(buf, gtk_entry_get_text(GTK_ENTRY(cli)), sizeof(buf) - 1); - gtk_entry_set_text(GTK_ENTRY(cli), ""); - if (strlen(buf)) { - ast_cli_command(clipipe[1], buf); - } - return TRUE; -} - -static int show_console(void) -{ - GtkWidget *hbox; - GtkWidget *wbox; - GtkWidget *notebook; - GtkWidget *sw; - GtkWidget *bbox, *hbbox, *add, *removew, *reloadw; - char *modtitles[3] = { "Module", "Description", "Use Count" }; - window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - - statusbar = gtk_statusbar_new(); - gtk_widget_show(statusbar); - - gtk_signal_connect(GTK_OBJECT(window), "delete_event", - GTK_SIGNAL_FUNC (exit_nicely), window); - gtk_signal_connect(GTK_OBJECT(window), "destroy", - GTK_SIGNAL_FUNC (exit_now), window); - gtk_container_set_border_width(GTK_CONTAINER(window), 10); - - quit = gtk_button_new_with_label("Quit Asterisk"); - gtk_signal_connect(GTK_OBJECT(quit), "clicked", - GTK_SIGNAL_FUNC (exit_completely), window); - gtk_widget_show(quit); - - closew = gtk_button_new_with_label("Close Window"); - gtk_signal_connect(GTK_OBJECT(closew), "clicked", - GTK_SIGNAL_FUNC (exit_nicely), window); - gtk_widget_show(closew); - - notebook = gtk_notebook_new(); - verb = gtk_clist_new(1); - gtk_clist_columns_autosize(GTK_CLIST(verb)); - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - gtk_container_add(GTK_CONTAINER(sw), verb); - gtk_widget_show(verb); - gtk_widget_show(sw); - gtk_widget_set_usize(verb, 640, 400); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), sw, gtk_label_new("Verbose Status")); - - - modules = gtk_clist_new_with_titles(3, modtitles); - gtk_clist_columns_autosize(GTK_CLIST(modules)); - gtk_clist_set_column_auto_resize(GTK_CLIST(modules), 0, TRUE); - gtk_clist_set_column_auto_resize(GTK_CLIST(modules), 1, TRUE); - gtk_clist_set_column_auto_resize(GTK_CLIST(modules), 2, TRUE); - gtk_clist_set_sort_column(GTK_CLIST(modules), 0); - gtk_clist_set_auto_sort(GTK_CLIST(modules), TRUE); - gtk_clist_column_titles_passive(GTK_CLIST(modules)); - sw = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - gtk_container_add(GTK_CONTAINER(sw), modules); - gtk_clist_set_selection_mode(GTK_CLIST(modules), GTK_SELECTION_BROWSE); - gtk_widget_show(modules); - gtk_widget_show(sw); - - add = gtk_button_new_with_label("Load..."); - gtk_widget_show(add); - removew = gtk_button_new_with_label("Unload"); - gtk_widget_show(removew); - reloadw = gtk_button_new_with_label("Reload"); - gtk_widget_show(reloadw); - gtk_signal_connect(GTK_OBJECT(removew), "clicked", - GTK_SIGNAL_FUNC (remove_module), window); - gtk_signal_connect(GTK_OBJECT(add), "clicked", - GTK_SIGNAL_FUNC (add_module), window); - gtk_signal_connect(GTK_OBJECT(reloadw), "clicked", - GTK_SIGNAL_FUNC (reload_module), window); - - bbox = gtk_vbox_new(FALSE, 5); - gtk_widget_show(bbox); - - gtk_widget_set_usize(bbox, 100, -1); - gtk_box_pack_start(GTK_BOX(bbox), add, FALSE, FALSE, 5); - gtk_box_pack_start(GTK_BOX(bbox), removew, FALSE, FALSE, 5); - gtk_box_pack_start(GTK_BOX(bbox), reloadw, FALSE, FALSE, 5); - - hbbox = gtk_hbox_new(FALSE, 5); - gtk_widget_show(hbbox); - - gtk_box_pack_start(GTK_BOX(hbbox), sw, TRUE, TRUE, 5); - gtk_box_pack_start(GTK_BOX(hbbox), bbox, FALSE, FALSE, 5); - - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), hbbox, gtk_label_new("Module Information")); - - gtk_widget_show(notebook); - - wbox = gtk_hbox_new(FALSE, 5); - gtk_widget_show(wbox); - gtk_box_pack_end(GTK_BOX(wbox), quit, FALSE, FALSE, 5); - gtk_box_pack_end(GTK_BOX(wbox), closew, FALSE, FALSE, 5); - - hbox = gtk_vbox_new(FALSE, 0); - gtk_widget_show(hbox); - - /* Command line */ - cli = gtk_entry_new(); - gtk_widget_show(cli); - - gtk_signal_connect(GTK_OBJECT(cli), "activate", - GTK_SIGNAL_FUNC (cli_activate), NULL); - - gtk_box_pack_start(GTK_BOX(hbox), notebook, TRUE, TRUE, 5); - gtk_box_pack_start(GTK_BOX(hbox), wbox, FALSE, FALSE, 5); - gtk_box_pack_start(GTK_BOX(hbox), cli, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(hbox), statusbar, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(window), hbox); - gtk_window_set_title(GTK_WINDOW(window), "Asterisk Console"); - gtk_widget_grab_focus(cli); - ast_pthread_create(&console_thread, NULL, consolethread, NULL); - /* XXX Okay, seriously fix me! XXX */ - usleep(100000); - ast_register_verbose(verboser); - gtk_clist_freeze(GTK_CLIST(verb)); - ast_loader_register(mod_update); - gtk_clist_thaw(GTK_CLIST(verb)); - gdk_input_add(clipipe[0], GDK_INPUT_READ, cliinput, NULL); - mod_update(); - update_statusbar("Asterisk Console Ready"); - return 0; -} - - -int load_module(void) -{ - if (pipe(clipipe)) { - ast_log(LOG_WARNING, "Unable to create CLI pipe\n"); - return -1; - } - g_thread_init(NULL); - if (gtk_init_check(NULL, NULL)) { - if (!show_console()) { - inuse++; - ast_update_use_count(); - if (option_verbose > 1) - ast_verbose( VERBOSE_PREFIX_2 "Launched GTK Console monitor\n"); - } else - ast_log(LOG_WARNING, "Unable to start GTK console\n"); - } else { - if (option_debug) - ast_log(LOG_DEBUG, "Unable to start GTK console monitor -- ignoring\n"); - else if (option_verbose > 1) - ast_verbose( VERBOSE_PREFIX_2 "GTK is not available -- skipping monitor\n"); - } - return 0; -} - -int usecount(void) -{ - return inuse; -} - -char *description(void) -{ - return dtext; -} - -char *key(void) -{ - return ASTERISK_GPL_KEY; -} diff --git a/1.2-netsec/pbx/pbx_kdeconsole.cc b/1.2-netsec/pbx/pbx_kdeconsole.cc deleted file mode 100644 index 6c2817366..000000000 --- a/1.2-netsec/pbx/pbx_kdeconsole.cc +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Asterisk -- A telephony toolkit for Linux. - * - * KDE Console monitor -- Class implmementation - * - * Copyright (C) 1999, Mark Spencer - * - * Mark Spencer <markster@linux-support.net> - * - * This program is free software, distributed under the terms of - * the GNU General Public License - */ - -#include "pbx_kdeconsole.moc" - -KAsteriskConsole::KAsteriskConsole() : KTMainWindow() -{ - QVBoxLayout *box; - QFrame *f; - - f = new QFrame(this); - - setGeometry(100,100,600,400); - /* Menus */ - file = new QPopupMenu(); - file->insertItem("&Exit", this, SLOT(slotExit())); - - help = kapp->getHelpMenu(TRUE, "KDE Asterisk Console\nby Mark Spencer"); - - setCaption("Asterisk Console"); - - /* Box */ - box = new QVBoxLayout(f, 20, 5); - - /* Menu bar creation */ - menu = new KMenuBar(this); - menu->insertItem("&File", file); - menu->insertItem("&Help", help); - /* Verbose stuff */ - verbose = new QListBox(f, "verbose"); - /* Exit button */ - btnExit = new QPushButton("Exit", f, "exit"); - btnExit->show(); - connect(btnExit, SIGNAL(clicked()), this, SLOT(slotExit())); - - box->addWidget(verbose, 1); - box->addWidget(btnExit, 0); - setView(f, TRUE); - statusBar()->message("Ready", 2000); -} - -void KAsteriskConsole::slotExit() -{ - close(); -} - -void KAsteriskConsole::closeEvent(QCloseEvent *) -{ - kapp->quit(); -} - diff --git a/1.2-netsec/pbx/pbx_kdeconsole.h b/1.2-netsec/pbx/pbx_kdeconsole.h deleted file mode 100644 index df73ab38e..000000000 --- a/1.2-netsec/pbx/pbx_kdeconsole.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Asterisk -- A telephony toolkit for Linux. - * - * KDE Console monitor -- Header file - * - * Copyright (C) 1999, Mark Spencer - * - * Mark Spencer <markster@linux-support.net> - * - * This program is free software, distributed under the terms of - * the GNU General Public License - */ - -#include <kapp.h> -#include <ktmainwindow.h> -#include <qpushbutton.h> -#include <kmenubar.h> -#include <qpopupmenu.h> -#include <qlistbox.h> -#include <qlayout.h> -#include <qframe.h> - -class KAsteriskConsole : public KTMainWindow -{ - Q_OBJECT -public: - KAsteriskConsole(); - void closeEvent(QCloseEvent *); - QListBox *verbose; -public slots: - void slotExit(); -private: - void KAsteriskConsole::verboser(char *stuff, int opos, int replacelast, int complete); - QPushButton *btnExit; - KMenuBar *menu; - QPopupMenu *file, *help; -}; diff --git a/1.2-netsec/pbx/pbx_kdeconsole_main.cc b/1.2-netsec/pbx/pbx_kdeconsole_main.cc deleted file mode 100644 index 0bb2d73e2..000000000 --- a/1.2-netsec/pbx/pbx_kdeconsole_main.cc +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Asterisk -- A telephony toolkit for Linux. - * - * KDE Console monitor -- Mostly glue code - * - * Copyright (C) 1999, Mark Spencer - * - * Mark Spencer <markster@linux-support.net> - * - * This program is free software, distributed under the terms of - * the GNU General Public License - */ - -#include "asterisk/module.h" -#include "asterisk/channel.h" -#include "asterisk/logger.h" -#include "asterisk/lock.h" -#include "pbx_kdeconsole.h" - -static char *dtext = "KDE Console Monitor"; - -static int inuse = 0; - -static KAsteriskConsole *w; - -static void verboser(char *stuff, int opos, int replacelast, int complete) -{ - const char *s2[2]; - s2[0] = stuff; - s2[1] = NULL; - if (replacelast) { - printf("Removing %d\n", w->verbose->count()); - w->verbose->removeItem(w->verbose->count()); - } - w->verbose->insertStrList(s2, 1, -1); - w->verbose->setBottomItem(w->verbose->count()); -} - -static int kde_main(int argc, char *argv[]) -{ - KApplication a ( argc, argv ); - w = new KAsteriskConsole(); - a.setMainWidget(w); - w->show(); - ast_register_verbose(verboser); - return a.exec(); -} - -static void *kdemain(void *data) -{ - /* It would appear kde really wants to be main */; - char *argv[1] = { "asteriskconsole" }; - kde_main(1, argv); - return NULL; -} - -extern "C" { - -int unload_module(void) -{ - return inuse; -} - -int load_module(void) -{ - pthread_t t; - pthread_create(&t, NULL, kdemain, NULL); - return 0; -} - -int usecount(void) -{ - return inuse; -} - -char *description(void) -{ - return dtext; -} - -} diff --git a/1.2-netsec/pbx/pbx_loopback.c b/1.2-netsec/pbx/pbx_loopback.c deleted file mode 100644 index 5522e9b09..000000000 --- a/1.2-netsec/pbx/pbx_loopback.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief Loopback PBX Module - * - */ - -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/file.h" -#include "asterisk/logger.h" -#include "asterisk/channel.h" -#include "asterisk/config.h" -#include "asterisk/options.h" -#include "asterisk/pbx.h" -#include "asterisk/module.h" -#include "asterisk/frame.h" -#include "asterisk/file.h" -#include "asterisk/cli.h" -#include "asterisk/lock.h" -#include "asterisk/md5.h" -#include "asterisk/linkedlists.h" -#include "asterisk/chanvars.h" -#include "asterisk/sched.h" -#include "asterisk/io.h" -#include "asterisk/utils.h" -#include "asterisk/crypto.h" -#include "asterisk/astdb.h" - -static char *tdesc = "Loopback Switch"; - -/* Loopback switch substitutes ${EXTEN}, ${CONTEXT}, and ${PRIORITY} into - the data passed to it to try to get a string of the form: - - [exten]@context[:priority][/extramatch] - - Where exten, context, and priority are another extension, context, and priority - to lookup and "extramatch" is an extra match restriction the *original* number - must fit if specified. The "extramatch" begins with _ like an exten pattern - if it is specified. Note that the search context MUST be a different context - from the current context or the search will not succeed in an effort to reduce - the likelihood of loops (they're still possible if you try hard, so be careful!) - -*/ - - -#define LOOPBACK_COMMON \ - char buf[1024]; \ - int res; \ - char *newexten=(char *)exten, *newcontext=(char *)context; \ - int newpriority=priority; \ - char *newpattern=NULL; \ - loopback_helper(buf, sizeof(buf), exten, context, priority, data); \ - loopback_subst(&newexten, &newcontext, &newpriority, &newpattern, buf); \ - ast_log(LOG_DEBUG, "Parsed into %s @ %s priority %d\n", newexten, newcontext, newpriority); \ - if (!strcasecmp(newcontext, context)) return -1 - - -static char *loopback_helper(char *buf, int buflen, const char *exten, const char *context, int priority, const char *data) -{ - struct ast_var_t *newvariable; - struct varshead headp; - char tmp[80]; - - snprintf(tmp, sizeof(tmp), "%d", priority); - memset(buf, 0, buflen); - AST_LIST_HEAD_INIT_NOLOCK(&headp); - newvariable = ast_var_assign("EXTEN", exten); - AST_LIST_INSERT_HEAD(&headp, newvariable, entries); - newvariable = ast_var_assign("CONTEXT", context); - AST_LIST_INSERT_HEAD(&headp, newvariable, entries); - newvariable = ast_var_assign("PRIORITY", tmp); - AST_LIST_INSERT_HEAD(&headp, newvariable, entries); - pbx_substitute_variables_varshead(&headp, data, buf, buflen); - /* Substitute variables */ - while (!AST_LIST_EMPTY(&headp)) { /* List Deletion. */ - newvariable = AST_LIST_REMOVE_HEAD(&headp, entries); - ast_var_delete(newvariable); - } - return buf; -} - -static void loopback_subst(char **newexten, char **newcontext, int *priority, char **newpattern, char *buf) -{ - char *con; - char *pri; - *newpattern = strchr(buf, '/'); - if (*newpattern) { - *(*newpattern) = '\0'; - (*newpattern)++; - } - con = strchr(buf, '@'); - if (con) { - *con = '\0'; - con++; - pri = strchr(con, ':'); - } else - pri = strchr(buf, ':'); - if (!ast_strlen_zero(buf)) - *newexten = buf; - if (!ast_strlen_zero(con)) - *newcontext = con; - if (!ast_strlen_zero(pri)) - sscanf(pri, "%d", priority); -} - -static int loopback_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) -{ - LOOPBACK_COMMON; - res = ast_exists_extension(chan, newcontext, newexten, newpriority, callerid); - if (newpattern && !ast_extension_match(newpattern, exten)) - res = 0; - return res; -} - -static int loopback_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) -{ - LOOPBACK_COMMON; - res = ast_canmatch_extension(chan, newcontext, newexten, newpriority, callerid); - if (newpattern && !ast_extension_match(newpattern, exten)) - res = 0; - return res; -} - -static int loopback_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, int newstack, const char *data) -{ - LOOPBACK_COMMON; - if (newstack) - res = ast_spawn_extension(chan, newcontext, newexten, newpriority, callerid); - else - res = ast_exec_extension(chan, newcontext, newexten, newpriority, callerid); - if (newpattern && !ast_extension_match(newpattern, exten)) - res = -1; - return res; -} - -static int loopback_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) -{ - LOOPBACK_COMMON; - res = ast_matchmore_extension(chan, newcontext, newexten, newpriority, callerid); - if (newpattern && !ast_extension_match(newpattern, exten)) - res = 0; - return res; -} - -static struct ast_switch loopback_switch = -{ - name: "Loopback", - description: "Loopback Dialplan Switch", - exists: loopback_exists, - canmatch: loopback_canmatch, - exec: loopback_exec, - matchmore: loopback_matchmore, -}; - -char *description(void) -{ - return tdesc; -} - -int usecount(void) -{ - return 1; -} - -char *key() -{ - return ASTERISK_GPL_KEY; -} - -int unload_module(void) -{ - ast_unregister_switch(&loopback_switch); - return 0; -} - -int load_module(void) -{ - ast_register_switch(&loopback_switch); - return 0; -} - diff --git a/1.2-netsec/pbx/pbx_realtime.c b/1.2-netsec/pbx/pbx_realtime.c deleted file mode 100644 index 4e9aba1fe..000000000 --- a/1.2-netsec/pbx/pbx_realtime.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief Realtime PBX Module - * - * \arg See also: \ref AstARA - */ - -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/file.h" -#include "asterisk/logger.h" -#include "asterisk/channel.h" -#include "asterisk/config.h" -#include "asterisk/options.h" -#include "asterisk/pbx.h" -#include "asterisk/module.h" -#include "asterisk/frame.h" -#include "asterisk/term.h" -#include "asterisk/manager.h" -#include "asterisk/file.h" -#include "asterisk/cli.h" -#include "asterisk/lock.h" -#include "asterisk/md5.h" -#include "asterisk/linkedlists.h" -#include "asterisk/chanvars.h" -#include "asterisk/sched.h" -#include "asterisk/io.h" -#include "asterisk/utils.h" -#include "asterisk/crypto.h" -#include "asterisk/astdb.h" - -#define MODE_MATCH 0 -#define MODE_MATCHMORE 1 -#define MODE_CANMATCH 2 - -#define EXT_DATA_SIZE 256 - -static char *tdesc = "Realtime Switch"; - -/* Realtime switch looks up extensions in the supplied realtime table. - - [context@][realtimetable][/options] - - If the realtimetable is omitted it is assumed to be "extensions". If no context is - specified the context is assumed to be whatever is the container. - - The realtime table should have entries for context,exten,priority,app,args - - The realtime table currently does not support callerid fields. - -*/ - - -#define REALTIME_COMMON(mode) \ - char *buf; \ - char *opts; \ - const char *cxt; \ - char *table; \ - int res=-1; \ - struct ast_variable *var=NULL; \ - buf = ast_strdupa(data); \ - if (buf) { \ - opts = strchr(buf, '/'); \ - if (opts) { \ - *opts='\0'; \ - opts++; \ - } else \ - opts=""; \ - table = strchr(buf, '@'); \ - if (table) { \ - *table = '\0'; \ - table++;\ - cxt = buf; \ - } else cxt = NULL; \ - if (ast_strlen_zero(cxt)) \ - cxt = context;\ - if (ast_strlen_zero(table)) \ - table = "extensions"; \ - var = realtime_switch_common(table, cxt, exten, priority, mode); \ - } else \ - res = -1; - -static struct ast_variable *realtime_switch_common(const char *table, const char *context, const char *exten, int priority, int mode) -{ - struct ast_variable *var; - struct ast_config *cfg; - char pri[20]; - char *ematch; - char rexten[AST_MAX_EXTENSION + 20]=""; - int match; - snprintf(pri, sizeof(pri), "%d", priority); - switch(mode) { - case MODE_MATCHMORE: - ematch = "exten LIKE"; - snprintf(rexten, sizeof(rexten), "%s_%%", exten); - break; - case MODE_CANMATCH: - ematch = "exten LIKE"; - snprintf(rexten, sizeof(rexten), "%s%%", exten); - break; - case MODE_MATCH: - default: - ematch = "exten"; - strncpy(rexten, exten, sizeof(rexten) - 1); - } - var = ast_load_realtime(table, ematch, rexten, "context", context, "priority", pri, NULL); - if (!var) { - cfg = ast_load_realtime_multientry(table, "exten LIKE", "\\_%", "context", context, "priority", pri, NULL); - if (cfg) { - char *cat = ast_category_browse(cfg, NULL); - - while(cat) { - switch(mode) { - case MODE_MATCHMORE: - match = ast_extension_close(cat, exten, 1); - break; - case MODE_CANMATCH: - match = ast_extension_close(cat, exten, 0); - break; - case MODE_MATCH: - default: - match = ast_extension_match(cat, exten); - } - if (match) { - var = ast_category_detach_variables(ast_category_get(cfg, cat)); - break; - } - cat = ast_category_browse(cfg, cat); - } - ast_config_destroy(cfg); - } - } - return var; -} - -static int realtime_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) -{ - REALTIME_COMMON(MODE_MATCH); - if (var) ast_variables_destroy(var); - if (var) - res = 1; - return res > 0 ? res : 0; -} - -static int realtime_canmatch(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) -{ - REALTIME_COMMON(MODE_CANMATCH); - if (var) ast_variables_destroy(var); - if (var) - res = 1; - return res > 0 ? res : 0; -} - -static int realtime_exec(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, int newstack, const char *data) -{ - char app[256]; - char appdata[512]=""; - char *tmp=""; - char tmp1[80]; - char tmp2[80]; - char tmp3[EXT_DATA_SIZE]; - struct ast_app *a; - struct ast_variable *v; - REALTIME_COMMON(MODE_MATCH); - if (var) { - v = var; - while(v) { - if (!strcasecmp(v->name, "app")) - strncpy(app, v->value, sizeof(app) -1 ); - else if (!strcasecmp(v->name, "appdata")) - tmp = ast_strdupa(v->value); - v = v->next; - } - ast_variables_destroy(var); - if (!ast_strlen_zero(app)) { - a = pbx_findapp(app); - if (a) { - if(!ast_strlen_zero(tmp)) - pbx_substitute_variables_helper(chan, tmp, appdata, sizeof(appdata) - 1); - if (option_verbose > 2) - ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\")\n", - term_color(tmp1, app, COLOR_BRCYAN, 0, sizeof(tmp1)), - term_color(tmp2, chan->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)), - term_color(tmp3, (!ast_strlen_zero(appdata) ? (char *)appdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3))); - manager_event(EVENT_FLAG_CALL, "Newexten", - "Channel: %s\r\n" - "Context: %s\r\n" - "Extension: %s\r\n" - "Priority: %d\r\n" - "Application: %s\r\n" - "AppData: %s\r\n" - "Uniqueid: %s\r\n", - chan->name, chan->context, chan->exten, chan->priority, app, appdata ? appdata : "(NULL)", chan->uniqueid); - - res = pbx_exec(chan, a, appdata, newstack); - } else - ast_log(LOG_NOTICE, "No such application '%s' for extension '%s' in context '%s'\n", app, exten, context); - } - } - return res; -} - -static int realtime_matchmore(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data) -{ - REALTIME_COMMON(MODE_MATCHMORE); - if (var) ast_variables_destroy(var); - if (var) - res = 1; - return res > 0 ? res : 0; -} - -static struct ast_switch realtime_switch = -{ - name: "Realtime", - description: "Realtime Dialplan Switch", - exists: realtime_exists, - canmatch: realtime_canmatch, - exec: realtime_exec, - matchmore: realtime_matchmore, -}; - -char *description(void) -{ - return tdesc; -} - -int usecount(void) -{ - return 1; -} - -char *key() -{ - return ASTERISK_GPL_KEY; -} - -int unload_module(void) -{ - ast_unregister_switch(&realtime_switch); - return 0; -} - -int load_module(void) -{ - ast_register_switch(&realtime_switch); - return 0; -} - diff --git a/1.2-netsec/pbx/pbx_spool.c b/1.2-netsec/pbx/pbx_spool.c deleted file mode 100644 index a91a7e255..000000000 --- a/1.2-netsec/pbx/pbx_spool.c +++ /dev/null @@ -1,445 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief Full-featured outgoing call spool support - * - */ - -#include <sys/stat.h> -#include <errno.h> -#include <time.h> -#include <utime.h> -#include <stdlib.h> -#include <unistd.h> -#include <dirent.h> -#include <string.h> -#include <string.h> -#include <stdio.h> -#include <unistd.h> - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/lock.h" -#include "asterisk/file.h" -#include "asterisk/logger.h" -#include "asterisk/channel.h" -#include "asterisk/callerid.h" -#include "asterisk/pbx.h" -#include "asterisk/module.h" -#include "asterisk/options.h" -#include "asterisk/utils.h" - -/* - * pbx_spool is similar in spirit to qcall, but with substantially enhanced functionality... - * The spool file contains a header - */ - -static char *tdesc = "Outgoing Spool Support"; -static char qdir[255]; - -struct outgoing { - char fn[256]; - /* Current number of retries */ - int retries; - /* Maximum number of retries permitted */ - int maxretries; - /* How long to wait between retries (in seconds) */ - int retrytime; - /* How long to wait for an answer */ - int waittime; - /* PID which is currently calling */ - int callingpid; - - /* What to connect to outgoing */ - char tech[256]; - char dest[256]; - - /* If application */ - char app[256]; - char data[256]; - - /* If extension/context/priority */ - char exten[256]; - char context[256]; - int priority; - - /* CallerID Information */ - char cid_num[256]; - char cid_name[256]; - - /* account code */ - char account[AST_MAX_ACCOUNT_CODE]; - - /* Variables and Functions */ - struct ast_variable *vars; - - /* Maximum length of call */ - int maxlen; -}; - -static void init_outgoing(struct outgoing *o) -{ - memset(o, 0, sizeof(struct outgoing)); - o->priority = 1; - o->retrytime = 300; - o->waittime = 45; -} - -static void free_outgoing(struct outgoing *o) -{ - free(o); -} - -static int apply_outgoing(struct outgoing *o, char *fn, FILE *f) -{ - char buf[256]; - char *c, *c2; - int lineno = 0; - struct ast_variable *var; - - while(fgets(buf, sizeof(buf), f)) { - lineno++; - /* Trim comments */ - c = buf; - while ((c = strchr(c, '#'))) { - if ((c == buf) || (*(c-1) == ' ') || (*(c-1) == '\t')) - *c = '\0'; - else - c++; - } - - c = buf; - while ((c = strchr(c, ';'))) { - if ((c > buf) && (c[-1] == '\\')) { - memmove(c - 1, c, strlen(c) + 1); - c++; - } else { - *c = '\0'; - break; - } - } - - /* Trim trailing white space */ - while(!ast_strlen_zero(buf) && buf[strlen(buf) - 1] < 33) - buf[strlen(buf) - 1] = '\0'; - if (!ast_strlen_zero(buf)) { - c = strchr(buf, ':'); - if (c) { - *c = '\0'; - c++; - while ((*c) && (*c < 33)) - c++; -#if 0 - printf("'%s' is '%s' at line %d\n", buf, c, lineno); -#endif - if (!strcasecmp(buf, "channel")) { - strncpy(o->tech, c, sizeof(o->tech) - 1); - if ((c2 = strchr(o->tech, '/'))) { - *c2 = '\0'; - c2++; - strncpy(o->dest, c2, sizeof(o->dest) - 1); - } else { - ast_log(LOG_NOTICE, "Channel should be in form Tech/Dest at line %d of %s\n", lineno, fn); - o->tech[0] = '\0'; - } - } else if (!strcasecmp(buf, "callerid")) { - ast_callerid_split(c, o->cid_name, sizeof(o->cid_name), o->cid_num, sizeof(o->cid_num)); - } else if (!strcasecmp(buf, "application")) { - strncpy(o->app, c, sizeof(o->app) - 1); - } else if (!strcasecmp(buf, "data")) { - strncpy(o->data, c, sizeof(o->data) - 1); - } else if (!strcasecmp(buf, "maxretries")) { - if (sscanf(c, "%d", &o->maxretries) != 1) { - ast_log(LOG_WARNING, "Invalid max retries at line %d of %s\n", lineno, fn); - o->maxretries = 0; - } - } else if (!strcasecmp(buf, "context")) { - strncpy(o->context, c, sizeof(o->context) - 1); - } else if (!strcasecmp(buf, "extension")) { - strncpy(o->exten, c, sizeof(o->exten) - 1); - } else if (!strcasecmp(buf, "priority")) { - if ((sscanf(c, "%d", &o->priority) != 1) || (o->priority < 1)) { - ast_log(LOG_WARNING, "Invalid priority at line %d of %s\n", lineno, fn); - o->priority = 1; - } - } else if (!strcasecmp(buf, "retrytime")) { - if ((sscanf(c, "%d", &o->retrytime) != 1) || (o->retrytime < 1)) { - ast_log(LOG_WARNING, "Invalid retrytime at line %d of %s\n", lineno, fn); - o->retrytime = 300; - } - } else if (!strcasecmp(buf, "waittime")) { - if ((sscanf(c, "%d", &o->waittime) != 1) || (o->waittime < 1)) { - ast_log(LOG_WARNING, "Invalid retrytime at line %d of %s\n", lineno, fn); - o->waittime = 45; - } - } else if (!strcasecmp(buf, "retry")) { - o->retries++; - } else if (!strcasecmp(buf, "startretry")) { - if (sscanf(c, "%d", &o->callingpid) != 1) { - ast_log(LOG_WARNING, "Unable to retrieve calling PID!\n"); - o->callingpid = 0; - } - } else if (!strcasecmp(buf, "endretry") || !strcasecmp(buf, "abortretry")) { - o->callingpid = 0; - o->retries++; - } else if (!strcasecmp(buf, "delayedretry")) { - } else if (!strcasecmp(buf, "setvar") || !strcasecmp(buf, "set")) { - c2 = c; - strsep(&c2, "="); - if (c2) { - var = ast_variable_new(c, c2); - if (var) { - var->next = o->vars; - o->vars = var; - } - } else { - ast_log(LOG_WARNING, "Malformed Set: argument! Should be Set: Variable=value\n"); - } - } else if (!strcasecmp(buf, "account")) { - ast_copy_string(o->account, c, sizeof(o->account)); - } else { - ast_log(LOG_WARNING, "Unknown keyword '%s' at line %d of %s\n", buf, lineno, fn); - } - } else - ast_log(LOG_NOTICE, "Syntax error at line %d of %s\n", lineno, fn); - } - } - strncpy(o->fn, fn, sizeof(o->fn) - 1); - if (ast_strlen_zero(o->tech) || ast_strlen_zero(o->dest) || (ast_strlen_zero(o->app) && ast_strlen_zero(o->exten))) { - ast_log(LOG_WARNING, "At least one of app or extension must be specified, along with tech and dest in file %s\n", fn); - return -1; - } - return 0; -} - -static void safe_append(struct outgoing *o, time_t now, char *s) -{ - int fd; - FILE *f; - struct utimbuf tbuf; - fd = open(o->fn, O_WRONLY|O_APPEND); - if (fd > -1) { - f = fdopen(fd, "a"); - if (f) { - fprintf(f, "%s: %ld %d (%ld)\n", s, (long)ast_mainpid, o->retries, (long) now); - fclose(f); - } else - close(fd); - /* Update the file time */ - tbuf.actime = now; - tbuf.modtime = now + o->retrytime; - if (utime(o->fn, &tbuf)) - ast_log(LOG_WARNING, "Unable to set utime on %s: %s\n", o->fn, strerror(errno)); - } -} - -static void *attempt_thread(void *data) -{ - struct outgoing *o = data; - int res, reason; - if (!ast_strlen_zero(o->app)) { - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Attempting call on %s/%s for application %s(%s) (Retry %d)\n", o->tech, o->dest, o->app, o->data, o->retries); - res = ast_pbx_outgoing_app(o->tech, AST_FORMAT_SLINEAR, o->dest, o->waittime * 1000, o->app, o->data, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, o->account, NULL); - } else { - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Attempting call on %s/%s for %s@%s:%d (Retry %d)\n", o->tech, o->dest, o->exten, o->context,o->priority, o->retries); - res = ast_pbx_outgoing_exten(o->tech, AST_FORMAT_SLINEAR, o->dest, o->waittime * 1000, o->context, o->exten, o->priority, &reason, 2 /* wait to finish */, o->cid_num, o->cid_name, o->vars, o->account, NULL); - } - if (res) { - ast_log(LOG_NOTICE, "Call failed to go through, reason %d\n", reason); - if (o->retries >= o->maxretries + 1) { - /* Max retries exceeded */ - ast_log(LOG_EVENT, "Queued call to %s/%s expired without completion after %d attempt%s\n", o->tech, o->dest, o->retries - 1, ((o->retries - 1) != 1) ? "s" : ""); - unlink(o->fn); - } else { - /* Notate that the call is still active */ - safe_append(o, time(NULL), "EndRetry"); - } - } else { - ast_log(LOG_NOTICE, "Call completed to %s/%s\n", o->tech, o->dest); - ast_log(LOG_EVENT, "Queued call to %s/%s completed\n", o->tech, o->dest); - unlink(o->fn); - } - free_outgoing(o); - return NULL; -} - -static void launch_service(struct outgoing *o) -{ - pthread_t t; - pthread_attr_t attr; - int ret; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - if ((ret = ast_pthread_create(&t,&attr,attempt_thread, o)) != 0) { - ast_log(LOG_WARNING, "Unable to create thread :( (returned error: %d)\n", ret); - free_outgoing(o); - } -} - -static int scan_service(char *fn, time_t now, time_t atime) -{ - struct outgoing *o; - FILE *f; - o = malloc(sizeof(struct outgoing)); - if (o) { - init_outgoing(o); - f = fopen(fn, "r+"); - if (f) { - if (!apply_outgoing(o, fn, f)) { -#if 0 - printf("Filename: %s, Retries: %d, max: %d\n", fn, o->retries, o->maxretries); -#endif - fclose(f); - if (o->retries <= o->maxretries) { - now += o->retrytime; - if (o->callingpid && (o->callingpid == ast_mainpid)) { - safe_append(o, time(NULL), "DelayedRetry"); - free_outgoing(o); - ast_log(LOG_DEBUG, "Delaying retry since we're currently running '%s'\n", o->fn); - } else { - /* Increment retries */ - o->retries++; - /* If someone else was calling, they're presumably gone now - so abort their retry and continue as we were... */ - if (o->callingpid) - safe_append(o, time(NULL), "AbortRetry"); - - safe_append(o, now, "StartRetry"); - launch_service(o); - } - return now; - } else { - ast_log(LOG_EVENT, "Queued call to %s/%s expired without completion after %d attempt%s\n", o->tech, o->dest, o->retries - 1, ((o->retries - 1) != 1) ? "s" : ""); - free_outgoing(o); - unlink(fn); - return 0; - } - } else { - free_outgoing(o); - ast_log(LOG_WARNING, "Invalid file contents in %s, deleting\n", fn); - fclose(f); - unlink(fn); - } - } else { - free_outgoing(o); - ast_log(LOG_WARNING, "Unable to open %s: %s, deleting\n", fn, strerror(errno)); - unlink(fn); - } - } else - ast_log(LOG_WARNING, "Out of memory :(\n"); - return -1; -} - -static void *scan_thread(void *unused) -{ - struct stat st; - DIR *dir; - struct dirent *de; - char fn[256]; - int res; - time_t last = 0, next = 0, now; - for(;;) { - /* Wait a sec */ - sleep(1); - time(&now); - if (!stat(qdir, &st)) { - if ((st.st_mtime != last) || (next && (now > next))) { -#if 0 - printf("atime: %ld, mtime: %ld, ctime: %ld\n", st.st_atime, st.st_mtime, st.st_ctime); - printf("Ooh, something changed / timeout\n"); -#endif - next = 0; - last = st.st_mtime; - dir = opendir(qdir); - if (dir) { - while((de = readdir(dir))) { - snprintf(fn, sizeof(fn), "%s/%s", qdir, de->d_name); - if (!stat(fn, &st)) { - if (S_ISREG(st.st_mode)) { - if (st.st_mtime <= now) { - res = scan_service(fn, now, st.st_atime); - if (res > 0) { - /* Update next service time */ - if (!next || (res < next)) { - next = res; - } - } else if (res) - ast_log(LOG_WARNING, "Failed to scan service '%s'\n", fn); - } else { - /* Update "next" update if necessary */ - if (!next || (st.st_mtime < next)) - next = st.st_mtime; - } - } - } else - ast_log(LOG_WARNING, "Unable to stat %s: %s\n", fn, strerror(errno)); - } - closedir(dir); - } else - ast_log(LOG_WARNING, "Unable to open directory %s: %s\n", qdir, strerror(errno)); - } - } else - ast_log(LOG_WARNING, "Unable to stat %s\n", qdir); - } - return NULL; -} - -int unload_module(void) -{ - return -1; -} - -int load_module(void) -{ - pthread_t thread; - pthread_attr_t attr; - int ret; - snprintf(qdir, sizeof(qdir), "%s/%s", ast_config_AST_SPOOL_DIR, "outgoing"); - if (mkdir(qdir, 0700) && (errno != EEXIST)) { - ast_log(LOG_WARNING, "Unable to create queue directory %s -- outgoing spool disabled\n", qdir); - return 0; - } - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - if ((ret = ast_pthread_create(&thread,&attr,scan_thread, NULL)) != 0) { - ast_log(LOG_WARNING, "Unable to create thread :( (returned error: %d)\n", ret); - return -1; - } - return 0; -} - -char *description(void) -{ - return tdesc; -} - -int usecount(void) -{ - return 1; -} - -char *key() -{ - return ASTERISK_GPL_KEY; -} |