/* * Asterisk -- A telephony toolkit for Linux. * * Hunt Implementation * * This program hunts through a series of extensions until one is picked up. * It is based on various Asterisk programs. * * Written March 2003 by * John Harragin * * Copyright (C) 2003, Digium * * Mark Spencer * * This program is free software, distributed under the terms of * the GNU General Public License */ #include #include #include #include #include #include #include #include #include #include #include // These next two macros must be defined in quotes #ifndef DFT_HUNT_TaO #define DFT_HUNT_TaO 10 #endif // DFT_SKIP_TaO may be defined externally for example //#define DFT_SKIP_TaO 8|t #define MAX_ARGS 24 // These next 2 macros are to get quotes around DFT_HUNT_TaO substitution #define _xstr(s) _str(s) #define _str(s) #s static char *tdesc = "Extension Hunt."; // a special hangup code could be added to dial to continuation into voicemail // I would need to keep better tabs on priority numbering //I can add default overides for timeout, ring... //hunt(HUNT_VAR,$skipdev,timeoutoverride,ringoverride,dialflags) //I might add skipdev|timeout - if timeout specified, skipdev rings - first static char *descrip = "Hunt(HUNT_VARIABLE_name|arg1|arg2...): Executes a hunt pattern using the current\n" "priority. One arguments must be passed HUNT_VARIABLE_name. A second argument\n" "skipdev (generally, the calling resource) will be skipped over - or if a\n" "timeout (or any additional dial options) are defined it will be dialed first\n" "then be skipped if it is uniquely defined in HUNT_VARIABLE_name.\n" "* HUNT_VARIABLE_name must be passed naked - that is with no $ or{}.\n" "* The HUNT_VARIABLE currently must be defined as a global variable.\n" "By default a timeout of DFT_HUNT_TaO and no additional options are passed to dial.\n" "These options remain in effect until new options are encountered in any\n" "HUNT_VARIABLE element. These will in turn become the new persistant values.\n" "HUNT_VARIABLE Example (note the use of pipes to delimit options and commas to\n" "delimit elements:\nHUNT_GROUP1=Zap/2,Zap/3|8,Zap/10,Zap/4\n" "Incantation Example:\nhunt(HUNT_GROUP1,Zap/10|5)\n" "Hunt returns -1 if any step in the hunt returns -1 and 0 otherwise. If skipdev\n" "was found to be busy 'dial' will increment the channel priority by 100.\n"; static char *app = "Hunt"; static char *synopsis = "Hunt Implementation"; STANDARD_LOCAL_USER; LOCAL_USER_DECL; static int hunt_exec(struct ast_channel *chan, void *data) { char ver_hunt[512] = ""; int verbose = 1; // This must be initialized from ast env char *timeout,*tmp_timeout,*sdtimeout; char *skipdev,*HUNT_VAR,*hunt_str,*tmp_ht_dev,*cur_h_dev; char tmp[256] = ""; char tmpv[256] = ""; char tmpstr[256]; char cur_h_to[128] = _xstr(DFT_HUNT_TaO); char dial_data[256] = ""; char *cur, *rest; char dial_app[] = "Dial"; int dres, priority; int res = 0; int argc = 1; struct ast_app *app; app = pbx_findapp(dial_app); if (!data || !strlen(data)) {// ast_log(LOG_WARNING, "Invalid Hunt incantation\n"); return 0; } ////////////// CpyAppData( appbu, app); strncpy(tmp, data, sizeof(tmp) - 1); rest = tmp; HUNT_VAR = strsep(&rest, "|"); skipdev = strsep(&rest, "|"); if (rest) { if (strlen(rest)) { sprintf(dial_data, "%s|%s", skipdev, rest); dres = pbx_exec(chan, app, dial_data, 1); } #ifdef DFT_SKIP_TaO } else if (strlen(_xstr(DFT_SKIP_TaO))) { sprintf(dial_data, "%s|%s", skipdev, _xstr(DFT_SKIP_TaO)); dres = pbx_exec(chan, app, dial_data, 1); } { #endif //NEXT LINR either add strlen(dial_data) to if or initialize. if (verbose) snprintf(ver_hunt, sizeof(ver_hunt), "Dialing %s returned %d.\n", dial_data, dres); if (dres == -1) { res = -1; goto out; } ////////////// CpyAppData( app, appbu); } priority = chan->priority; // store if subsequent dials alter this hunt_str = pbx_builtin_getvar_helper(NULL, HUNT_VAR); // see global access if (hunt_str) { strncpy(tmpv, hunt_str, sizeof(tmpv) - 1); rest = tmpv; while(tmp_ht_dev = strsep(&rest, ",")) { cur_h_dev = strsep(&tmp_ht_dev, "|"); // Deconstruct sting for future paramter manipulation if(tmp_ht_dev) strncpy(cur_h_to, tmp_ht_dev, sizeof(cur_h_to) - 1); if(strcmp(skipdev, cur_h_dev)) { sprintf(dial_data, "%s|%s", cur_h_dev, cur_h_to); dres = pbx_exec(chan, app, dial_data, 1); if (verbose) { snprintf(tmpstr, sizeof(tmpstr), "Hunt element %s returned %d.\n", dial_data, dres); strncat(ver_hunt, tmpstr, sizeof(ver_hunt)); } if (dres == -1) { res = -1; break; } ////////////// CpyAppData( app, appbu); } else { if (verbose) { snprintf(tmpstr, sizeof(tmpstr), "Hunt element %s skipped.\n", dial_data); strncat(ver_hunt, tmpstr, sizeof(ver_hunt)); } } if (MAX_ARGS <= argc++) { snprintf(ver_hunt, sizeof(ver_hunt), "%sMaximum hunt elements processed. %s ignored.\n", ver_hunt, rest); ast_log(LOG_WARNING, "%s", ver_hunt); } } } else { ast_log(LOG_WARNING, "No valid global hunt variable specified\n"); return 0; } chan->priority = priority; out: if (verbose) ast_verbose( VERBOSE_PREFIX_2 "%s", ver_hunt); return res; } /* // Save this shit until deciding how to inspect dres done... if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F'))) { // Just return result as to the previous application as if it had been dialed // ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res); break; // this does nothing here } switch(res) { case AST_PBX_KEEPALIVE: if (option_debug) ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE in hunt %s on '%s'\n", chan->context, chan->exten, chan->priority, hunt, chan->name); else if (option_verbose > 1) ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE in hunt '%s' on '%s'\n", chan->context, chan->exten, chan->priority, hunt, chan->name); goto out; break; default: if (option_debug) ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s' in hunt '%s'\n", chan->context, chan->exten, chan->priority, chan->name, hunt); else if (option_verbose > 1) ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s' in hunt '%s'\n", chan->context, chan->exten, chan->priority, chan->name, hunt); goto out; } if (strcasecmp(chan->context, fullhunt)) { if (option_verbose > 1) ast_verbose(VERBOSE_PREFIX_2 "Channel '%s' jumping out of hunt '%s'\n", chan->name, hunt); break; } if (chan->_softhangup) { ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n", chan->exten, chan->priority); goto out; } */ int unload_module(void) { STANDARD_HANGUP_LOCALUSERS; return ast_unregister_application(app); } int load_module(void) { return ast_register_application(app, hunt_exec, synopsis, descrip); } char *description(void) { return tdesc; } int usecount(void) { int res; STANDARD_USECOUNT(res); return res; } char *key() { return ASTERISK_GPL_KEY; }