#include "asterisk.h"
#include <sys/stat.h>
#include <time.h>
#include <utime.h>
#include <dirent.h>
#include "asterisk/paths.h"
#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/utils.h"
#include "asterisk/options.h"
Go to the source code of this file.
Data Structures | |
struct | outgoing |
Enumerations | |
enum | { SPOOL_FLAG_ALWAYS_DELETE = (1 << 0), SPOOL_FLAG_ARCHIVE = (1 << 1) } |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | apply_outgoing (struct outgoing *o, char *fn, FILE *f) |
static void * | attempt_thread (void *data) |
static void | free_outgoing (struct outgoing *o) |
static void | init_outgoing (struct outgoing *o) |
static void | launch_service (struct outgoing *o) |
static int | load_module (void) |
static int | remove_from_queue (struct outgoing *o, const char *status) |
Remove a call file from the outgoing queue optionally moving it in the archive dir. | |
static void | safe_append (struct outgoing *o, time_t now, char *s) |
static int | scan_service (char *fn, time_t now, time_t atime) |
static void * | scan_thread (void *unused) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Outgoing Spool Support" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, } |
static const struct ast_module_info * | ast_module_info = &__mod_info |
static char | qdir [255] |
static char | qdonedir [255] |
Definition in file pbx_spool.c.
anonymous enum |
Definition at line 50 of file pbx_spool.c.
00050 { 00051 /*! Always delete the call file after a call succeeds or the 00052 * maximum number of retries is exceeded, even if the 00053 * modification time of the call file is in the future. 00054 */ 00055 SPOOL_FLAG_ALWAYS_DELETE = (1 << 0), 00056 /* Don't unlink the call file after processing, move in qdonedir */ 00057 SPOOL_FLAG_ARCHIVE = (1 << 1) 00058 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 533 of file pbx_spool.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 533 of file pbx_spool.c.
static int apply_outgoing | ( | struct outgoing * | o, | |
char * | fn, | |||
FILE * | f | |||
) | [static] |
Definition at line 122 of file pbx_spool.c.
References outgoing::account, outgoing::app, ast_callerid_split(), ast_copy_string(), ast_log(), ast_parse_allow_disallow(), ast_set2_flag, ast_strlen_zero(), ast_true(), ast_variable_new(), buf, outgoing::callingpid, outgoing::cid_name, outgoing::cid_num, outgoing::context, outgoing::data, outgoing::dest, outgoing::exten, outgoing::fn, outgoing::format, last, LOG_NOTICE, LOG_WARNING, outgoing::maxretries, ast_event_ref::next, outgoing::options, outgoing::priority, outgoing::retries, outgoing::retrytime, SPOOL_FLAG_ALWAYS_DELETE, SPOOL_FLAG_ARCHIVE, strsep(), outgoing::tech, var, outgoing::vars, and outgoing::waittime.
Referenced by scan_service().
00123 { 00124 char buf[256]; 00125 char *c, *c2; 00126 int lineno = 0; 00127 struct ast_variable *var, *last = o->vars; 00128 00129 while (last && last->next) { 00130 last = last->next; 00131 } 00132 00133 while(fgets(buf, sizeof(buf), f)) { 00134 lineno++; 00135 /* Trim comments */ 00136 c = buf; 00137 while ((c = strchr(c, '#'))) { 00138 if ((c == buf) || (*(c-1) == ' ') || (*(c-1) == '\t')) 00139 *c = '\0'; 00140 else 00141 c++; 00142 } 00143 00144 c = buf; 00145 while ((c = strchr(c, ';'))) { 00146 if ((c > buf) && (c[-1] == '\\')) { 00147 memmove(c - 1, c, strlen(c) + 1); 00148 c++; 00149 } else { 00150 *c = '\0'; 00151 break; 00152 } 00153 } 00154 00155 /* Trim trailing white space */ 00156 while(!ast_strlen_zero(buf) && buf[strlen(buf) - 1] < 33) 00157 buf[strlen(buf) - 1] = '\0'; 00158 if (!ast_strlen_zero(buf)) { 00159 c = strchr(buf, ':'); 00160 if (c) { 00161 *c = '\0'; 00162 c++; 00163 while ((*c) && (*c < 33)) 00164 c++; 00165 #if 0 00166 printf("'%s' is '%s' at line %d\n", buf, c, lineno); 00167 #endif 00168 if (!strcasecmp(buf, "channel")) { 00169 ast_copy_string(o->tech, c, sizeof(o->tech)); 00170 if ((c2 = strchr(o->tech, '/'))) { 00171 *c2 = '\0'; 00172 c2++; 00173 ast_copy_string(o->dest, c2, sizeof(o->dest)); 00174 } else { 00175 ast_log(LOG_NOTICE, "Channel should be in form Tech/Dest at line %d of %s\n", lineno, fn); 00176 o->tech[0] = '\0'; 00177 } 00178 } else if (!strcasecmp(buf, "callerid")) { 00179 ast_callerid_split(c, o->cid_name, sizeof(o->cid_name), o->cid_num, sizeof(o->cid_num)); 00180 } else if (!strcasecmp(buf, "application")) { 00181 ast_copy_string(o->app, c, sizeof(o->app)); 00182 } else if (!strcasecmp(buf, "data")) { 00183 ast_copy_string(o->data, c, sizeof(o->data)); 00184 } else if (!strcasecmp(buf, "maxretries")) { 00185 if (sscanf(c, "%d", &o->maxretries) != 1) { 00186 ast_log(LOG_WARNING, "Invalid max retries at line %d of %s\n", lineno, fn); 00187 o->maxretries = 0; 00188 } 00189 } else if (!strcasecmp(buf, "codecs")) { 00190 ast_parse_allow_disallow(NULL, &o->format, c, 1); 00191 } else if (!strcasecmp(buf, "context")) { 00192 ast_copy_string(o->context, c, sizeof(o->context)); 00193 } else if (!strcasecmp(buf, "extension")) { 00194 ast_copy_string(o->exten, c, sizeof(o->exten)); 00195 } else if (!strcasecmp(buf, "priority")) { 00196 if ((sscanf(c, "%d", &o->priority) != 1) || (o->priority < 1)) { 00197 ast_log(LOG_WARNING, "Invalid priority at line %d of %s\n", lineno, fn); 00198 o->priority = 1; 00199 } 00200 } else if (!strcasecmp(buf, "retrytime")) { 00201 if ((sscanf(c, "%d", &o->retrytime) != 1) || (o->retrytime < 1)) { 00202 ast_log(LOG_WARNING, "Invalid retrytime at line %d of %s\n", lineno, fn); 00203 o->retrytime = 300; 00204 } 00205 } else if (!strcasecmp(buf, "waittime")) { 00206 if ((sscanf(c, "%d", &o->waittime) != 1) || (o->waittime < 1)) { 00207 ast_log(LOG_WARNING, "Invalid waittime at line %d of %s\n", lineno, fn); 00208 o->waittime = 45; 00209 } 00210 } else if (!strcasecmp(buf, "retry")) { 00211 o->retries++; 00212 } else if (!strcasecmp(buf, "startretry")) { 00213 if (sscanf(c, "%ld", &o->callingpid) != 1) { 00214 ast_log(LOG_WARNING, "Unable to retrieve calling PID!\n"); 00215 o->callingpid = 0; 00216 } 00217 } else if (!strcasecmp(buf, "endretry") || !strcasecmp(buf, "abortretry")) { 00218 o->callingpid = 0; 00219 o->retries++; 00220 } else if (!strcasecmp(buf, "delayedretry")) { 00221 } else if (!strcasecmp(buf, "setvar") || !strcasecmp(buf, "set")) { 00222 c2 = c; 00223 strsep(&c2, "="); 00224 if (c2) { 00225 var = ast_variable_new(c, c2, fn); 00226 if (var) { 00227 /* Always insert at the end, because some people want to treat the spool file as a script */ 00228 if (last) { 00229 last->next = var; 00230 } else { 00231 o->vars = var; 00232 } 00233 last = var; 00234 } 00235 } else 00236 ast_log(LOG_WARNING, "Malformed \"%s\" argument. Should be \"%s: variable=value\"\n", buf, buf); 00237 } else if (!strcasecmp(buf, "account")) { 00238 ast_copy_string(o->account, c, sizeof(o->account)); 00239 } else if (!strcasecmp(buf, "alwaysdelete")) { 00240 ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_ALWAYS_DELETE); 00241 } else if (!strcasecmp(buf, "archive")) { 00242 ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_ARCHIVE); 00243 } else { 00244 ast_log(LOG_WARNING, "Unknown keyword '%s' at line %d of %s\n", buf, lineno, fn); 00245 } 00246 } else 00247 ast_log(LOG_NOTICE, "Syntax error at line %d of %s\n", lineno, fn); 00248 } 00249 } 00250 ast_copy_string(o->fn, fn, sizeof(o->fn)); 00251 if (ast_strlen_zero(o->tech) || ast_strlen_zero(o->dest) || (ast_strlen_zero(o->app) && ast_strlen_zero(o->exten))) { 00252 ast_log(LOG_WARNING, "At least one of app or extension must be specified, along with tech and dest in file %s\n", fn); 00253 return -1; 00254 } 00255 return 0; 00256 }
static void* attempt_thread | ( | void * | data | ) | [static] |
Definition at line 335 of file pbx_spool.c.
References outgoing::account, outgoing::app, ast_channel_reason2str(), ast_log(), ast_pbx_outgoing_app(), ast_pbx_outgoing_exten(), ast_strlen_zero(), ast_verb, outgoing::cid_name, outgoing::cid_num, outgoing::context, outgoing::data, outgoing::dest, outgoing::exten, outgoing::format, free_outgoing(), LOG_EVENT, LOG_NOTICE, outgoing::maxretries, outgoing::priority, remove_from_queue(), outgoing::retries, safe_append(), outgoing::tech, outgoing::vars, and outgoing::waittime.
Referenced by launch_service().
00336 { 00337 struct outgoing *o = data; 00338 int res, reason; 00339 if (!ast_strlen_zero(o->app)) { 00340 ast_verb(3, "Attempting call on %s/%s for application %s(%s) (Retry %d)\n", o->tech, o->dest, o->app, o->data, o->retries); 00341 res = ast_pbx_outgoing_app(o->tech, o->format, 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); 00342 } else { 00343 ast_verb(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); 00344 res = ast_pbx_outgoing_exten(o->tech, o->format, 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); 00345 } 00346 if (res) { 00347 ast_log(LOG_NOTICE, "Call failed to go through, reason (%d) %s\n", reason, ast_channel_reason2str(reason)); 00348 if (o->retries >= o->maxretries + 1) { 00349 /* Max retries exceeded */ 00350 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" : ""); 00351 remove_from_queue(o, "Expired"); 00352 } else { 00353 /* Notate that the call is still active */ 00354 safe_append(o, time(NULL), "EndRetry"); 00355 } 00356 } else { 00357 ast_log(LOG_NOTICE, "Call completed to %s/%s\n", o->tech, o->dest); 00358 ast_log(LOG_EVENT, "Queued call to %s/%s completed\n", o->tech, o->dest); 00359 remove_from_queue(o, "Completed"); 00360 } 00361 free_outgoing(o); 00362 return NULL; 00363 }
static void free_outgoing | ( | struct outgoing * | o | ) | [static] |
Definition at line 117 of file pbx_spool.c.
References ast_free.
Referenced by attempt_thread(), launch_service(), and scan_service().
00118 { 00119 ast_free(o); 00120 }
static void init_outgoing | ( | struct outgoing * | o | ) | [static] |
Definition at line 108 of file pbx_spool.c.
References AST_FORMAT_SLINEAR, ast_set_flag, outgoing::format, outgoing::options, outgoing::priority, outgoing::retrytime, SPOOL_FLAG_ALWAYS_DELETE, and outgoing::waittime.
Referenced by scan_service().
00109 { 00110 o->priority = 1; 00111 o->retrytime = 300; 00112 o->waittime = 45; 00113 o->format = AST_FORMAT_SLINEAR; 00114 ast_set_flag(&o->options, SPOOL_FLAG_ALWAYS_DELETE); 00115 }
static void launch_service | ( | struct outgoing * | o | ) | [static] |
Definition at line 365 of file pbx_spool.c.
References ast_log(), ast_pthread_create_detached, attempt_thread(), free_outgoing(), and LOG_WARNING.
Referenced by scan_service().
00366 { 00367 pthread_t t; 00368 int ret; 00369 00370 if ((ret = ast_pthread_create_detached(&t, NULL, attempt_thread, o))) { 00371 ast_log(LOG_WARNING, "Unable to create thread :( (returned error: %d)\n", ret); 00372 free_outgoing(o); 00373 } 00374 }
static int load_module | ( | void | ) | [static] |
Definition at line 514 of file pbx_spool.c.
References ast_config_AST_SPOOL_DIR, ast_log(), ast_mkdir(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_pthread_create_detached_background, LOG_WARNING, scan_thread(), and thread.
00515 { 00516 pthread_t thread; 00517 int ret; 00518 snprintf(qdir, sizeof(qdir), "%s/%s", ast_config_AST_SPOOL_DIR, "outgoing"); 00519 if (ast_mkdir(qdir, 0777)) { 00520 ast_log(LOG_WARNING, "Unable to create queue directory %s -- outgoing spool disabled\n", qdir); 00521 return AST_MODULE_LOAD_DECLINE; 00522 } 00523 snprintf(qdonedir, sizeof(qdir), "%s/%s", ast_config_AST_SPOOL_DIR, "outgoing_done"); 00524 00525 if ((ret = ast_pthread_create_detached_background(&thread, NULL, scan_thread, NULL))) { 00526 ast_log(LOG_WARNING, "Unable to create thread :( (returned error: %d)\n", ret); 00527 return AST_MODULE_LOAD_FAILURE; 00528 } 00529 00530 return AST_MODULE_LOAD_SUCCESS; 00531 }
static int remove_from_queue | ( | struct outgoing * | o, | |
const char * | status | |||
) | [static] |
Remove a call file from the outgoing queue optionally moving it in the archive dir.
o | the pointer to outgoing struct | |
status | the exit status of the call. Can be "Completed", "Failed" or "Expired" |
Definition at line 286 of file pbx_spool.c.
References ast_log(), ast_mkdir(), ast_test_flag, f, outgoing::fn, LOG_WARNING, outgoing::options, SPOOL_FLAG_ALWAYS_DELETE, and SPOOL_FLAG_ARCHIVE.
00287 { 00288 int fd; 00289 FILE *f; 00290 char newfn[256]; 00291 const char *bname; 00292 00293 if (!ast_test_flag(&o->options, SPOOL_FLAG_ALWAYS_DELETE)) { 00294 struct stat current_file_status; 00295 00296 if (!stat(o->fn, ¤t_file_status)) { 00297 if (time(NULL) < current_file_status.st_mtime) 00298 return 0; 00299 } 00300 } 00301 00302 if (!ast_test_flag(&o->options, SPOOL_FLAG_ARCHIVE)) { 00303 unlink(o->fn); 00304 return 0; 00305 } 00306 00307 if (ast_mkdir(qdonedir, 0777)) { 00308 ast_log(LOG_WARNING, "Unable to create queue directory %s -- outgoing spool archiving disabled\n", qdonedir); 00309 unlink(o->fn); 00310 return -1; 00311 } 00312 00313 if ((fd = open(o->fn, O_WRONLY | O_APPEND))) { 00314 if ((f = fdopen(fd, "a"))) { 00315 fprintf(f, "Status: %s\n", status); 00316 fclose(f); 00317 } else 00318 close(fd); 00319 } 00320 00321 if (!(bname = strrchr(o->fn, '/'))) 00322 bname = o->fn; 00323 else 00324 bname++; 00325 snprintf(newfn, sizeof(newfn), "%s/%s", qdonedir, bname); 00326 /* a existing call file the archive dir is overwritten */ 00327 unlink(newfn); 00328 if (rename(o->fn, newfn) != 0) { 00329 unlink(o->fn); 00330 return -1; 00331 } else 00332 return 0; 00333 }
static void safe_append | ( | struct outgoing * | o, | |
time_t | now, | |||
char * | s | |||
) | [static] |
Definition at line 258 of file pbx_spool.c.
References ast_log(), ast_mainpid, errno, f, outgoing::fn, LOG_WARNING, outgoing::retries, and outgoing::retrytime.
Referenced by attempt_thread(), and scan_service().
00259 { 00260 int fd; 00261 FILE *f; 00262 struct utimbuf tbuf; 00263 00264 if ((fd = open(o->fn, O_WRONLY | O_APPEND)) < 0) 00265 return; 00266 00267 if ((f = fdopen(fd, "a"))) { 00268 fprintf(f, "\n%s: %ld %d (%ld)\n", s, (long)ast_mainpid, o->retries, (long) now); 00269 fclose(f); 00270 } else 00271 close(fd); 00272 00273 /* Update the file time */ 00274 tbuf.actime = now; 00275 tbuf.modtime = now + o->retrytime; 00276 if (utime(o->fn, &tbuf)) 00277 ast_log(LOG_WARNING, "Unable to set utime on %s: %s\n", o->fn, strerror(errno)); 00278 }
static int scan_service | ( | char * | fn, | |
time_t | now, | |||
time_t | atime | |||
) | [static] |
Definition at line 376 of file pbx_spool.c.
References apply_outgoing(), ast_calloc, ast_log(), ast_mainpid, errno, f, free_outgoing(), init_outgoing(), launch_service(), LOG_DEBUG, LOG_EVENT, LOG_WARNING, remove_from_queue(), and safe_append().
Referenced by scan_thread().
00377 { 00378 struct outgoing *o = NULL; 00379 FILE *f; 00380 int res = 0; 00381 00382 if (!(o = ast_calloc(1, sizeof(*o)))) { 00383 ast_log(LOG_WARNING, "Out of memory ;(\n"); 00384 return -1; 00385 } 00386 00387 init_outgoing(o); 00388 00389 /* Attempt to open the file */ 00390 if (!(f = fopen(fn, "r+"))) { 00391 remove_from_queue(o, "Failed"); 00392 free_outgoing(o); 00393 ast_log(LOG_WARNING, "Unable to open %s: %s, deleting\n", fn, strerror(errno)); 00394 return -1; 00395 } 00396 00397 /* Read in and verify the contents */ 00398 if (apply_outgoing(o, fn, f)) { 00399 remove_from_queue(o, "Failed"); 00400 free_outgoing(o); 00401 ast_log(LOG_WARNING, "Invalid file contents in %s, deleting\n", fn); 00402 fclose(f); 00403 return -1; 00404 } 00405 00406 #if 0 00407 printf("Filename: %s, Retries: %d, max: %d\n", fn, o->retries, o->maxretries); 00408 #endif 00409 fclose(f); 00410 if (o->retries <= o->maxretries) { 00411 now += o->retrytime; 00412 if (o->callingpid && (o->callingpid == ast_mainpid)) { 00413 safe_append(o, time(NULL), "DelayedRetry"); 00414 ast_log(LOG_DEBUG, "Delaying retry since we're currently running '%s'\n", o->fn); 00415 free_outgoing(o); 00416 } else { 00417 /* Increment retries */ 00418 o->retries++; 00419 /* If someone else was calling, they're presumably gone now 00420 so abort their retry and continue as we were... */ 00421 if (o->callingpid) 00422 safe_append(o, time(NULL), "AbortRetry"); 00423 00424 safe_append(o, now, "StartRetry"); 00425 launch_service(o); 00426 } 00427 res = now; 00428 } else { 00429 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" : ""); 00430 remove_from_queue(o, "Expired"); 00431 free_outgoing(o); 00432 } 00433 00434 return res; 00435 }
static void* scan_thread | ( | void * | unused | ) | [static] |
Definition at line 437 of file pbx_spool.c.
References ast_fully_booted, ast_log(), dir, errno, last, LOG_WARNING, and scan_service().
Referenced by load_module().
00438 { 00439 struct stat st; 00440 DIR *dir; 00441 struct dirent *de; 00442 char fn[256]; 00443 int res; 00444 time_t last = 0, next = 0, now; 00445 struct timespec ts = { .tv_sec = 1 }; 00446 00447 while (!ast_fully_booted) { 00448 nanosleep(&ts, NULL); 00449 } 00450 00451 for(;;) { 00452 /* Wait a sec */ 00453 nanosleep(&ts, NULL); 00454 time(&now); 00455 00456 if (stat(qdir, &st)) { 00457 ast_log(LOG_WARNING, "Unable to stat %s\n", qdir); 00458 continue; 00459 } 00460 00461 /* Make sure it is time for us to execute our check */ 00462 if ((st.st_mtime == last) && (next && (next > now))) 00463 continue; 00464 00465 #if 0 00466 printf("atime: %ld, mtime: %ld, ctime: %ld\n", st.st_atime, st.st_mtime, st.st_ctime); 00467 printf("Ooh, something changed / timeout\n"); 00468 #endif 00469 next = 0; 00470 last = st.st_mtime; 00471 00472 if (!(dir = opendir(qdir))) { 00473 ast_log(LOG_WARNING, "Unable to open directory %s: %s\n", qdir, strerror(errno)); 00474 continue; 00475 } 00476 00477 while ((de = readdir(dir))) { 00478 snprintf(fn, sizeof(fn), "%s/%s", qdir, de->d_name); 00479 if (stat(fn, &st)) { 00480 ast_log(LOG_WARNING, "Unable to stat %s: %s\n", fn, strerror(errno)); 00481 continue; 00482 } 00483 if (!S_ISREG(st.st_mode)) 00484 continue; 00485 if (st.st_mtime <= now) { 00486 res = scan_service(fn, now, st.st_atime); 00487 if (res > 0) { 00488 /* Update next service time */ 00489 if (!next || (res < next)) { 00490 next = res; 00491 } 00492 } else if (res) { 00493 ast_log(LOG_WARNING, "Failed to scan service '%s'\n", fn); 00494 } else if (!next) { 00495 /* Expired entry: must recheck on the next go-around */ 00496 next = st.st_mtime; 00497 } 00498 } else { 00499 /* Update "next" update if necessary */ 00500 if (!next || (st.st_mtime < next)) 00501 next = st.st_mtime; 00502 } 00503 } 00504 closedir(dir); 00505 } 00506 return NULL; 00507 }
static int unload_module | ( | void | ) | [static] |
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Outgoing Spool Support" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 533 of file pbx_spool.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 533 of file pbx_spool.c.
char qdir[255] [static] |
Definition at line 60 of file pbx_spool.c.
char qdonedir[255] [static] |
Definition at line 61 of file pbx_spool.c.