Add option to register extensions on IAX or SIP registration
authorMark Spencer <markster@digium.com>
Tue, 7 Sep 2004 23:45:34 +0000 (23:45 +0000)
committerMark Spencer <markster@digium.com>
Tue, 7 Sep 2004 23:45:34 +0000 (23:45 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@3746 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_iax2.c
channels/chan_sip.c
configs/iax.conf.sample
configs/sip.conf.sample

index 44a0f3c..d218c88 100755 (executable)
@@ -3,7 +3,7 @@
  *
  * Implementation of Inter-Asterisk eXchange Version 2
  *
- * Copyright (C) 2003, Digium
+ * Copyright (C) 2003-2004, Digium, Inc.
  *
  * Mark Spencer <markster@digium.com>
  *
@@ -114,6 +114,7 @@ static char *type = "IAX2";
 static char context[80] = "default";
 
 static char language[MAX_LANGUAGE] = "";
+static char regcontext[AST_MAX_EXTENSION] = "";
 
 static int max_retries = 4;
 static int ping_time = 20;
@@ -219,6 +220,7 @@ struct iax2_peer {
        char secret[80];
        char outkey[80];                /* What key we use to talk to this peer */
        char context[AST_MAX_EXTENSION];        /* Default context (for transfer really) */
+       char regexten[AST_MAX_EXTENSION];       /* Extension to register (if regcontext is used) */
        char peercontext[AST_MAX_EXTENSION];    /* Context to pass to peer */
        char mailbox[AST_MAX_EXTENSION];        /* Mailbox */
        struct sockaddr_in addr;
@@ -4211,6 +4213,22 @@ static int iax2_register(char *value, int lineno)
        return 0;
 }
 
+static void register_peer_exten(struct iax2_peer *peer, int onoff)
+{
+       unsigned char multi[256]="";
+       char *stringp, *ext;
+       if (!ast_strlen_zero(regcontext)) {
+               strncpy(multi, ast_strlen_zero(peer->regexten) ? peer->name : peer->regexten, sizeof(multi) - 1);
+               stringp = multi;
+               while((ext = strsep(&stringp, "&"))) {
+                       if (onoff)
+                               ast_add_extension(regcontext, 1, ext, 1, NULL, "Noop", strdup(peer->name), free, type);
+                       else
+                               ast_context_remove_extension(regcontext, ext, 1, NULL);
+               }
+       }
+}
+
 static int expire_registry(void *data)
 {
        struct iax2_peer *p = data;
@@ -4221,6 +4239,7 @@ static int expire_registry(void *data)
        /* Reset expirey value */
        p->expirey = expirey;
        ast_db_del("IAX/Registry", p->name);
+       register_peer_exten(p, 0);
        if (iax2_regfunk)
                iax2_regfunk(p->name, 0);
        return 0;
@@ -4259,6 +4278,7 @@ static void reg_source_db(struct iax2_peer *p)
                                        p->expire = ast_sched_add(sched, p->expirey * 1000, expire_registry, (void *)p);
                                        if (iax2_regfunk)
                                                iax2_regfunk(p->name, 1);
+                                       register_peer_exten(p, 1);
                                }                                       
                                        
                        }
@@ -4294,15 +4314,18 @@ static int update_registry(char *name, struct sockaddr_in *sin, int callno, char
                        if (iax2_regfunk)
                                iax2_regfunk(p->name, 1);
                        snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port), p->expirey);
-                       ast_db_put("IAX/Registry", p->name, data);
                        if (sin->sin_addr.s_addr) {
+                               ast_db_put("IAX/Registry", p->name, data);
                                if  (option_verbose > 2)
                                ast_verbose(VERBOSE_PREFIX_3 "Registered '%s' (%s) at %s:%d\n", p->name, 
                                        iaxs[callno]->state & IAX_STATE_AUTHENTICATED ? "AUTHENTICATED" : "UNAUTHENTICATED", ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr), ntohs(sin->sin_port));
+                               register_peer_exten(p, 1);
                        } else {
                                if  (option_verbose > 2)
                                ast_verbose(VERBOSE_PREFIX_3 "Unregistered '%s' (%s)\n", p->name, 
                                        iaxs[callno]->state & IAX_STATE_AUTHENTICATED ? "AUTHENTICATED" : "UNAUTHENTICATED");
+                               register_peer_exten(p, 0);
+                               ast_db_del("IAX/Registry", p->name);
                        }
                        /* Update the host */
                        memcpy(&p->addr, sin, sizeof(p->addr));
@@ -6291,6 +6314,8 @@ static struct iax2_peer *build_peer(char *name, struct ast_variable *v)
                        } else if (!strcasecmp(v->name, "context")) {
                                if (ast_strlen_zero(peer->context))
                                        strncpy(peer->context, v->value, sizeof(peer->context) - 1);
+                       } else if (!strcasecmp(v->name, "regexten")) {
+                               strncpy(peer->regexten, v->value, sizeof(peer->regexten) - 1);
                        } else if (!strcasecmp(v->name, "peercontext")) {
                                if (ast_strlen_zero(peer->peercontext))
                                        strncpy(peer->peercontext, v->value, sizeof(peer->peercontext) - 1);
@@ -6552,6 +6577,7 @@ static void prune_peers(void){
                                ast_sched_del(sched, peer->pokeexpire);
                        if (peer->callno > 0)
                                iax2_destroy(peer->callno);
+                       register_peer_exten(peer, 0);
                        free(peer);
                        if (peerlast)
                                peerlast->next = peernext;
@@ -6669,6 +6695,11 @@ static int set_config(char *config_file, struct sockaddr_in* sin){
                        iax2_register(v->value, v->lineno);
                } else if (!strcasecmp(v->name, "iaxcompat")) {
                        iaxcompat = ast_true(v->value);
+               } else if (!strcasecmp(v->name, "regcontext")) {
+                       strncpy(regcontext, v->value, sizeof(regcontext) - 1);
+                       /* Create context if it doesn't exist already */
+                       if (!ast_context_find(regcontext))
+                               ast_context_create(NULL, regcontext, type);
                } else if (!strcasecmp(v->name, "tos")) {
                        if (sscanf(v->value, "%i", &format) == 1)
                                tos = format & 0xff;
index 5659b0b..c14fd44 100755 (executable)
@@ -203,6 +203,7 @@ static int global_promiscredir;
 
 static char global_musicclass[MAX_LANGUAGE] = "";      /* Global music on hold class */
 static char global_realm[AST_MAX_EXTENSION] = "asterisk";      /* Default realm */
+static char regcontext[AST_MAX_EXTENSION] = "";
 
 /* Expire slowly */
 static int expiry = 900;
@@ -422,6 +423,7 @@ struct sip_peer {
        char context[80];               /* JK02: peers need context too to allow parking etc */
        char username[80];
        char tohost[80];
+       char regexten[AST_MAX_EXTENSION];       /* Extension to register (if regcontext is used) */
        char fromuser[80];
        char fromdomain[80];
        char fullcontact[128];
@@ -4210,12 +4212,29 @@ static int transmit_request_with_auth(struct sip_pvt *p, char *msg, int seqno, i
        return send_request(p, &resp, reliable, seqno ? seqno : p->ocseq);      
 }
 
+static void register_peer_exten(struct sip_peer *peer, int onoff)
+{
+       unsigned char multi[256]="";
+       char *stringp, *ext;
+       if (!ast_strlen_zero(regcontext)) {
+               strncpy(multi, ast_strlen_zero(peer->regexten) ? peer->name : peer->regexten, sizeof(multi) - 1);
+               stringp = multi;
+               while((ext = strsep(&stringp, "&"))) {
+                       if (onoff)
+                               ast_add_extension(regcontext, 1, ext, 1, NULL, "Noop", strdup(peer->name), free, type);
+                       else
+                               ast_context_remove_extension(regcontext, ext, 1, NULL);
+               }
+       }
+}
+
 /*--- expire_register: Expire registration of SIP peer ---*/
 static int expire_register(void *data)
 {
        struct sip_peer *p = data;
        memset(&p->addr, 0, sizeof(p->addr));
        ast_db_del("SIP/Registry", p->name);
+       register_peer_exten(p, 0);
        p->expire = -1;
        ast_device_state_changed("SIP/%s", p->name);
        if (p->selfdestruct) {
@@ -4269,6 +4288,7 @@ static void reg_source_db(struct sip_peer *p)
                                        if (p->expire > -1)
                                                ast_sched_del(sched, p->expire);
                                        p->expire = ast_sched_add(sched, (expiry + 10) * 1000, expire_register, (void *)p);
+                                       register_peer_exten(p, 1);
                                }                                       
                                        
                        }
@@ -4318,6 +4338,7 @@ static int parse_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_req
                        ast_sched_del(sched, p->expire);
                p->expire = -1;
                ast_db_del("SIP/Registry", p->name);
+               register_peer_exten(p, 0);
                p->fullcontact[0] = '\0';
                p->useragent[0] = '\0';
                p->lastms = 0;
@@ -4387,6 +4408,7 @@ static int parse_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_req
                sip_poke_peer(p);
                if (option_verbose > 2)
                        ast_verbose(VERBOSE_PREFIX_3 "Registered SIP '%s' at %s port %d expires %d\n", p->name, ast_inet_ntoa(iabuf, sizeof(iabuf), p->addr.sin_addr), ntohs(p->addr.sin_port), expiry);
+               register_peer_exten(p, 1);
        }
 
        /* Save User agent */
@@ -8254,6 +8276,8 @@ static struct sip_peer *build_peer(char *name, struct ast_variable *v)
                                strncpy(peer->username, v->value, sizeof(peer->username)-1);
                        } else if (!strcasecmp(v->name, "language")) {
                                strncpy(peer->language, v->value, sizeof(peer->language)-1);
+                       } else if (!strcasecmp(v->name, "regexten")) {
+                               strncpy(peer->regexten, v->value, sizeof(peer->regexten)-1);
                        } else if (!strcasecmp(v->name, "musiconhold")) {
                                strncpy(peer->musicclass, v->value, sizeof(peer->musicclass)-1);
                        } else if (!strcasecmp(v->name, "mailbox")) {
@@ -8425,6 +8449,11 @@ static int reload_config(void)
                        strncpy(global_musicclass, v->value, sizeof(global_musicclass) - 1);
                } else if (!strcasecmp(v->name, "language")) {
                        strncpy(default_language, v->value, sizeof(default_language)-1);
+               } else if (!strcasecmp(v->name, "regcontext")) {
+                       strncpy(regcontext, v->value, sizeof(regcontext) - 1);
+                       /* Create context if it doesn't exist already */
+                       if (!ast_context_find(regcontext))
+                               ast_context_create(NULL, regcontext, type);
                } else if (!strcasecmp(v->name, "callerid")) {
                        strncpy(default_callerid, v->value, sizeof(default_callerid)-1);
                } else if (!strcasecmp(v->name, "fromdomain")) {
@@ -8834,6 +8863,7 @@ static void prune_peers(void)
                                ast_sched_del(sched, peer->expire);
                        if (peer->pokeexpire > -1)
                                ast_sched_del(sched, peer->pokeexpire);
+                       register_peer_exten(peer, 0);
                        free(peer);
                        if (peerlast)
                                peerlast->next = peernext;
index ff1543f..6068ce6 100755 (executable)
@@ -152,6 +152,15 @@ tos=lowdelay
 ;
 ;mailboxdetail=yes
 ;
+; If regcontext is specified, Asterisk will dynamically 
+; create and destroy a NoOp priority 1 extension for a given
+; peer who registers or unregisters with us.  The actual extension
+; is the 'regexten' parameter of the registering peer or its
+; name if 'regexten' is not provided.  More than one regexten may be supplied
+; if they are separated by '&'.  Patterns may be used in regexten.
+;
+;regcontext=iaxregistrations
+;
 ; Guest sections for unauthenticated connection attempts.  Just
 ; specify an empty secret, or provide no secret section.
 ;
@@ -262,6 +271,7 @@ host=216.207.245.47
 ;[marko]
 ;type=friend
 ;host=dynamic
+;regexten=1234
 ;secret=moofoo
 ;context=default
 ;permit=0.0.0.0/0.0.0.0
index 8dc3d32..de46d94 100755 (executable)
@@ -71,6 +71,16 @@ srvlookup=yes                        ; Enable DNS SRV lookups on outbound calls
 ;                       ; Note that promiscredir when redirects are made to the
 ;                       ; local system will cause loops since SIP is incapable
 ;                       ; of performing a "hairpin" call.
+;
+; If regcontext is specified, Asterisk will dynamically 
+; create and destroy a NoOp priority 1 extension for a given
+; peer who registers or unregisters with us.  The actual extension
+; is the 'regexten' parameter of the registering peer or its
+; name if 'regexten' is not provided.  More than one regexten may be supplied
+; if they are separated by '&'.  Patterns may be used in regexten.
+;
+;regcontext=iaxregistrations
+;
 ; Asterisk can register as a SIP user agent to a SIP proxy (provider)
 ; Format for the register statement is:
 ;       register => user[:secret[:authuser]]@host[:port][/extension]
@@ -145,6 +155,7 @@ srvlookup=yes                       ; Enable DNS SRV lookups on outbound calls
 ;                             username
 ;                             template
 ;                             fromdomain
+;                             regexten
 ;                             fromuser
 ;                             host
 ;                             mask
@@ -190,6 +201,7 @@ srvlookup=yes                       ; Enable DNS SRV lookups on outbound calls
 ;Turn off silence suppression in X-Lite ("Transmit Silence"=YES)!
 ;Note that Xlite sends NAT keep-alive packets, so qualify=yes is not needed
 ;type=friend
+;regexten=1234                 ; When they register, create extension 1234
 ;username=xlite1
 ;callerid="Jane Smith" <5678>
 ;host=dynamic