00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 #include "asterisk.h"
00054
00055 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 141267 $")
00056
00057 #include <stdlib.h>
00058 #include <errno.h>
00059 #include <unistd.h>
00060 #include <string.h>
00061 #include <stdlib.h>
00062 #include <stdio.h>
00063 #include <sys/time.h>
00064 #include <sys/stat.h>
00065 #include <sys/types.h>
00066 #include <sys/mman.h>
00067 #include <time.h>
00068 #include <dirent.h>
00069 #ifdef IMAP_STORAGE
00070 #include <ctype.h>
00071 #include <signal.h>
00072 #include <pwd.h>
00073 #ifdef USE_SYSTEM_IMAP
00074 #include <imap/c-client.h>
00075 #include <imap/imap4r1.h>
00076 #include <imap/linkage.h>
00077 #elif defined (USE_SYSTEM_CCLIENT)
00078 #include <c-client/c-client.h>
00079 #include <c-client/imap4r1.h>
00080 #include <c-client/linkage.h>
00081 #else
00082 #include "c-client.h"
00083 #include "imap4r1.h"
00084 #include "linkage.h"
00085 #endif
00086 #endif
00087 #include "asterisk/lock.h"
00088 #include "asterisk/file.h"
00089 #include "asterisk/logger.h"
00090 #include "asterisk/channel.h"
00091 #include "asterisk/pbx.h"
00092 #include "asterisk/options.h"
00093 #include "asterisk/config.h"
00094 #include "asterisk/say.h"
00095 #include "asterisk/module.h"
00096 #include "asterisk/adsi.h"
00097 #include "asterisk/app.h"
00098 #include "asterisk/manager.h"
00099 #include "asterisk/dsp.h"
00100 #include "asterisk/localtime.h"
00101 #include "asterisk/cli.h"
00102 #include "asterisk/utils.h"
00103 #include "asterisk/stringfields.h"
00104 #include "asterisk/smdi.h"
00105 #ifdef ODBC_STORAGE
00106 #include "asterisk/res_odbc.h"
00107 #endif
00108
00109 #ifdef IMAP_STORAGE
00110 AST_MUTEX_DEFINE_STATIC(imaptemp_lock);
00111 static char imaptemp[1024];
00112 static char imapserver[48];
00113 static char imapport[8];
00114 static char imapflags[128];
00115 static char imapfolder[64];
00116 static char authuser[32];
00117 static char authpassword[42];
00118
00119 static int expungeonhangup = 1;
00120 static char delimiter = '\0';
00121 static const long DEFAULT_IMAP_TCP_TIMEOUT = 60L;
00122
00123 struct vm_state;
00124 struct ast_vm_user;
00125
00126 static int init_mailstream (struct vm_state *vms, int box);
00127 static void write_file (char *filename, char *buffer, unsigned long len);
00128
00129 static char *get_header_by_tag(char *header, char *tag);
00130 static void vm_imap_delete(int msgnum, struct ast_vm_user *vmu);
00131 static char *get_user_by_mailbox(char *mailbox);
00132 static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive);
00133 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00134 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00135 static void vmstate_insert(struct vm_state *vms);
00136 static void vmstate_delete(struct vm_state *vms);
00137 static void set_update(MAILSTREAM * stream);
00138 static void init_vm_state(struct vm_state *vms);
00139 static void copy_msgArray(struct vm_state *dst, struct vm_state *src);
00140 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format);
00141 static void get_mailbox_delimiter(MAILSTREAM *stream);
00142 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00143 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00144 static int imap_store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms);
00145 static void check_quota(struct vm_state *vms, char *mailbox);
00146 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box);
00147 struct vmstate {
00148 struct vm_state *vms;
00149 struct vmstate *next;
00150 };
00151 AST_MUTEX_DEFINE_STATIC(vmstate_lock);
00152 static struct vmstate *vmstates = NULL;
00153 #endif
00154
00155 #define SMDI_MWI_WAIT_TIMEOUT 1000
00156
00157 #define COMMAND_TIMEOUT 5000
00158
00159 #define VOICEMAIL_DIR_MODE 0777
00160 #define VOICEMAIL_FILE_MODE 0666
00161 #define CHUNKSIZE 65536
00162
00163 #define VOICEMAIL_CONFIG "voicemail.conf"
00164 #define ASTERISK_USERNAME "asterisk"
00165
00166
00167
00168 #define SENDMAIL "/usr/sbin/sendmail -t"
00169
00170 #define INTRO "vm-intro"
00171
00172 #define MAXMSG 100
00173 #ifndef IMAP_STORAGE
00174 #define MAXMSGLIMIT 9999
00175 #else
00176 #define MAXMSGLIMIT 255
00177 #endif
00178
00179 #define BASEMAXINLINE 256
00180 #define BASELINELEN 72
00181 #define BASEMAXINLINE 256
00182 #define eol "\r\n"
00183
00184 #define MAX_DATETIME_FORMAT 512
00185 #define MAX_NUM_CID_CONTEXTS 10
00186
00187 #define VM_REVIEW (1 << 0)
00188 #define VM_OPERATOR (1 << 1)
00189 #define VM_SAYCID (1 << 2)
00190 #define VM_SVMAIL (1 << 3)
00191 #define VM_ENVELOPE (1 << 4)
00192 #define VM_SAYDURATION (1 << 5)
00193 #define VM_SKIPAFTERCMD (1 << 6)
00194 #define VM_FORCENAME (1 << 7)
00195 #define VM_FORCEGREET (1 << 8)
00196 #define VM_PBXSKIP (1 << 9)
00197 #define VM_DIRECFORWARD (1 << 10)
00198 #define VM_ATTACH (1 << 11)
00199 #define VM_DELETE (1 << 12)
00200 #define VM_ALLOCED (1 << 13)
00201 #define VM_SEARCH (1 << 14)
00202 #define VM_TEMPGREETWARN (1 << 15)
00203 #define ERROR_LOCK_PATH -100
00204 #define ERROR_MAILBOX_FULL -200
00205
00206
00207 enum {
00208 OPT_SILENT = (1 << 0),
00209 OPT_BUSY_GREETING = (1 << 1),
00210 OPT_UNAVAIL_GREETING = (1 << 2),
00211 OPT_RECORDGAIN = (1 << 3),
00212 OPT_PREPEND_MAILBOX = (1 << 4),
00213 OPT_PRIORITY_JUMP = (1 << 5),
00214 OPT_AUTOPLAY = (1 << 6),
00215 } vm_option_flags;
00216
00217 enum {
00218 OPT_ARG_RECORDGAIN = 0,
00219 OPT_ARG_PLAYFOLDER = 1,
00220
00221 OPT_ARG_ARRAY_SIZE = 2,
00222 } vm_option_args;
00223
00224 AST_APP_OPTIONS(vm_app_options, {
00225 AST_APP_OPTION('s', OPT_SILENT),
00226 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00227 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00228 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00229 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00230 AST_APP_OPTION('j', OPT_PRIORITY_JUMP),
00231 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00232 });
00233
00234 static int load_config(void);
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315 struct baseio {
00316 int iocp;
00317 int iolen;
00318 int linelength;
00319 int ateof;
00320 unsigned char iobuf[BASEMAXINLINE];
00321 };
00322
00323
00324 struct ast_vm_user {
00325 char context[AST_MAX_CONTEXT];
00326 char mailbox[AST_MAX_EXTENSION];
00327 char password[80];
00328 char fullname[80];
00329 char email[80];
00330 char pager[80];
00331 char serveremail[80];
00332 char mailcmd[160];
00333 char language[MAX_LANGUAGE];
00334 char zonetag[80];
00335 char callback[80];
00336 char dialout[80];
00337 char uniqueid[80];
00338 char exit[80];
00339 char attachfmt[20];
00340 unsigned int flags;
00341 int saydurationm;
00342 int maxmsg;
00343 #ifdef IMAP_STORAGE
00344 char imapuser[80];
00345 char imappassword[80];
00346 #endif
00347 double volgain;
00348 AST_LIST_ENTRY(ast_vm_user) list;
00349 };
00350
00351 struct vm_zone {
00352 AST_LIST_ENTRY(vm_zone) list;
00353 char name[80];
00354 char timezone[80];
00355 char msg_format[512];
00356 };
00357
00358 struct vm_state {
00359 char curbox[80];
00360 char username[80];
00361 char context[80];
00362 char curdir[PATH_MAX];
00363 char vmbox[PATH_MAX];
00364 char fn[PATH_MAX];
00365 char fn2[PATH_MAX];
00366 int *deleted;
00367 int *heard;
00368 int curmsg;
00369 int lastmsg;
00370 int newmessages;
00371 int oldmessages;
00372 int starting;
00373 int repeats;
00374 #ifdef IMAP_STORAGE
00375 ast_mutex_t lock;
00376 int updated;
00377 long msgArray[256];
00378 MAILSTREAM *mailstream;
00379 int vmArrayIndex;
00380 char imapuser[80];
00381 int interactive;
00382 unsigned int quota_limit;
00383 unsigned int quota_usage;
00384 struct vm_state *persist_vms;
00385 #endif
00386 };
00387 static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option, signed char record_gain);
00388 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00389 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00390 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
00391 signed char record_gain, struct vm_state *vms);
00392 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00393 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00394 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname);
00395 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap);
00396 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00397 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00398 #endif
00399 static void apply_options(struct ast_vm_user *vmu, const char *options);
00400
00401 #ifdef ODBC_STORAGE
00402 static char odbc_database[80];
00403 static char odbc_table[80];
00404 #define RETRIEVE(a,b,c) retrieve_file(a,b)
00405 #define DISPOSE(a,b) remove_file(a,b)
00406 #define STORE(a,b,c,d,e,f,g,h,i) store_file(a,b,c,d)
00407 #define EXISTS(a,b,c,d) (message_exists(a,b))
00408 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00409 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00410 #define DELETE(a,b,c,d) (delete_file(a,b))
00411 #else
00412 #ifdef IMAP_STORAGE
00413 #define RETRIEVE(a,b,c) imap_retrieve_file(a,b,c)
00414 #define DISPOSE(a,b) remove_file(a,b)
00415 #define STORE(a,b,c,d,e,f,g,h,i) (imap_store_file(a,b,c,d,e,f,g,h,i))
00416 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00417 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00418 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00419 #define DELETE(a,b,c,d) (vm_imap_delete(b,d))
00420 #else
00421 #define RETRIEVE(a,b,c)
00422 #define DISPOSE(a,b)
00423 #define STORE(a,b,c,d,e,f,g,h,i)
00424 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00425 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00426 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00427 #define DELETE(a,b,c,d) (vm_delete(c))
00428 #endif
00429 #endif
00430
00431 static char VM_SPOOL_DIR[PATH_MAX];
00432
00433 static char ext_pass_cmd[128];
00434
00435 int my_umask;
00436
00437 #if ODBC_STORAGE
00438 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00439 #elif IMAP_STORAGE
00440 #define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00441 #else
00442 #define tdesc "Comedian Mail (Voicemail System)"
00443 #endif
00444
00445 static char userscontext[AST_MAX_EXTENSION] = "default";
00446
00447 static char *addesc = "Comedian Mail";
00448
00449 static char *synopsis_vm =
00450 "Leave a Voicemail message";
00451
00452 static char *descrip_vm =
00453 " VoiceMail(mailbox[@context][&mailbox[@context]][...][|options]): This\n"
00454 "application allows the calling party to leave a message for the specified\n"
00455 "list of mailboxes. When multiple mailboxes are specified, the greeting will\n"
00456 "be taken from the first mailbox specified. Dialplan execution will stop if the\n"
00457 "specified mailbox does not exist.\n"
00458 " The Voicemail application will exit if any of the following DTMF digits are\n"
00459 "received:\n"
00460 " 0 - Jump to the 'o' extension in the current dialplan context.\n"
00461 " * - Jump to the 'a' extension in the current dialplan context.\n"
00462 " This application will set the following channel variable upon completion:\n"
00463 " VMSTATUS - This indicates the status of the execution of the VoiceMail\n"
00464 " application. The possible values are:\n"
00465 " SUCCESS | USEREXIT | FAILED\n\n"
00466 " Options:\n"
00467 " b - Play the 'busy' greeting to the calling party.\n"
00468 " g(#) - Use the specified amount of gain when recording the voicemail\n"
00469 " message. The units are whole-number decibels (dB).\n"
00470 " Only works on supported technologies, which is Zap only.\n"
00471 " s - Skip the playback of instructions for leaving a message to the\n"
00472 " calling party.\n"
00473 " u - Play the 'unavailable' greeting.\n"
00474 " j - Jump to priority n+101 if the mailbox is not found or some other\n"
00475 " error occurs.\n";
00476
00477 static char *synopsis_vmain =
00478 "Check Voicemail messages";
00479
00480 static char *descrip_vmain =
00481 " VoiceMailMain([mailbox][@context][|options]): This application allows the\n"
00482 "calling party to check voicemail messages. A specific mailbox, and optional\n"
00483 "corresponding context, may be specified. If a mailbox is not provided, the\n"
00484 "calling party will be prompted to enter one. If a context is not specified,\n"
00485 "the 'default' context will be used.\n\n"
00486 " Options:\n"
00487 " p - Consider the mailbox parameter as a prefix to the mailbox that\n"
00488 " is entered by the caller.\n"
00489 " g(#) - Use the specified amount of gain when recording a voicemail\n"
00490 " message. The units are whole-number decibels (dB).\n"
00491 " s - Skip checking the passcode for the mailbox.\n"
00492 " a(#) - Skip folder prompt and go directly to folder specified.\n"
00493 " Defaults to INBOX\n";
00494
00495 static char *synopsis_vm_box_exists =
00496 "Check to see if Voicemail mailbox exists";
00497
00498 static char *descrip_vm_box_exists =
00499 " MailboxExists(mailbox[@context][|options]): Check to see if the specified\n"
00500 "mailbox exists. If no voicemail context is specified, the 'default' context\n"
00501 "will be used.\n"
00502 " This application will set the following channel variable upon completion:\n"
00503 " VMBOXEXISTSSTATUS - This will contain the status of the execution of the\n"
00504 " MailboxExists application. Possible values include:\n"
00505 " SUCCESS | FAILED\n\n"
00506 " Options:\n"
00507 " j - Jump to priority n+101 if the mailbox is found.\n";
00508
00509 static char *synopsis_vmauthenticate =
00510 "Authenticate with Voicemail passwords";
00511
00512 static char *descrip_vmauthenticate =
00513 " VMAuthenticate([mailbox][@context][|options]): This application behaves the\n"
00514 "same way as the Authenticate application, but the passwords are taken from\n"
00515 "voicemail.conf.\n"
00516 " If the mailbox is specified, only that mailbox's password will be considered\n"
00517 "valid. If the mailbox is not specified, the channel variable AUTH_MAILBOX will\n"
00518 "be set with the authenticated mailbox.\n\n"
00519 " Options:\n"
00520 " s - Skip playing the initial prompts.\n";
00521
00522
00523 static char *app = "VoiceMail";
00524
00525
00526 static char *app2 = "VoiceMailMain";
00527
00528 static char *app3 = "MailboxExists";
00529 static char *app4 = "VMAuthenticate";
00530
00531 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00532 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00533 static int maxsilence;
00534 static int maxmsg;
00535 static int silencethreshold = 128;
00536 static char serveremail[80];
00537 static char mailcmd[160];
00538 static char externnotify[160];
00539 static struct ast_smdi_interface *smdi_iface = NULL;
00540 static char vmfmts[80];
00541 static double volgain;
00542 static int vmminmessage;
00543 static int vmmaxmessage;
00544 static int maxgreet;
00545 static int skipms;
00546 static int maxlogins;
00547
00548 static struct ast_flags globalflags = {0};
00549
00550 static int saydurationminfo;
00551
00552 static char dialcontext[AST_MAX_CONTEXT];
00553 static char callcontext[AST_MAX_CONTEXT];
00554 static char exitcontext[AST_MAX_CONTEXT];
00555
00556 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00557
00558
00559 static char *emailbody = NULL;
00560 static char *emailsubject = NULL;
00561 static char *pagerbody = NULL;
00562 static char *pagersubject = NULL;
00563 static char fromstring[100];
00564 static char pagerfromstring[100];
00565 static char emailtitle[100];
00566 static char charset[32] = "ISO-8859-1";
00567
00568 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00569 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00570 static int adsiver = 1;
00571 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00572
00573
00574 static char *strip_control(const char *input, char *buf, size_t buflen)
00575 {
00576 char *bufptr = buf;
00577 for (; *input; input++) {
00578 if (*input < 32) {
00579 continue;
00580 }
00581 *bufptr++ = *input;
00582 if (bufptr == buf + buflen - 1) {
00583 break;
00584 }
00585 }
00586 *bufptr = '\0';
00587 return buf;
00588 }
00589
00590 static void populate_defaults(struct ast_vm_user *vmu)
00591 {
00592 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
00593 if (saydurationminfo)
00594 vmu->saydurationm = saydurationminfo;
00595 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
00596 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
00597 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
00598 if (maxmsg)
00599 vmu->maxmsg = maxmsg;
00600 vmu->volgain = volgain;
00601 }
00602
00603 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
00604 {
00605 int x;
00606 if (!strcasecmp(var, "attach")) {
00607 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
00608 } else if (!strcasecmp(var, "attachfmt")) {
00609 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
00610 } else if (!strcasecmp(var, "serveremail")) {
00611 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
00612 } else if (!strcasecmp(var, "language")) {
00613 ast_copy_string(vmu->language, value, sizeof(vmu->language));
00614 } else if (!strcasecmp(var, "tz")) {
00615 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
00616 #ifdef IMAP_STORAGE
00617 } else if (!strcasecmp(var, "imapuser")) {
00618 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
00619 } else if (!strcasecmp(var, "imappassword")) {
00620 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
00621 #endif
00622 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
00623 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
00624 } else if (!strcasecmp(var, "saycid")){
00625 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
00626 } else if (!strcasecmp(var,"sendvoicemail")){
00627 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
00628 } else if (!strcasecmp(var, "review")){
00629 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
00630 } else if (!strcasecmp(var, "tempgreetwarn")){
00631 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
00632 } else if (!strcasecmp(var, "operator")){
00633 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
00634 } else if (!strcasecmp(var, "envelope")){
00635 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
00636 } else if (!strcasecmp(var, "sayduration")){
00637 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
00638 } else if (!strcasecmp(var, "saydurationm")){
00639 if (sscanf(value, "%d", &x) == 1) {
00640 vmu->saydurationm = x;
00641 } else {
00642 ast_log(LOG_WARNING, "Invalid min duration for say duration\n");
00643 }
00644 } else if (!strcasecmp(var, "forcename")){
00645 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
00646 } else if (!strcasecmp(var, "forcegreetings")){
00647 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
00648 } else if (!strcasecmp(var, "callback")) {
00649 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
00650 } else if (!strcasecmp(var, "dialout")) {
00651 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
00652 } else if (!strcasecmp(var, "exitcontext")) {
00653 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
00654 } else if (!strcasecmp(var, "maxmsg")) {
00655 vmu->maxmsg = atoi(value);
00656 if (vmu->maxmsg <= 0) {
00657 ast_log(LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %i\n", value, MAXMSG);
00658 vmu->maxmsg = MAXMSG;
00659 } else if (vmu->maxmsg > MAXMSGLIMIT) {
00660 ast_log(LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
00661 vmu->maxmsg = MAXMSGLIMIT;
00662 }
00663 } else if (!strcasecmp(var, "volgain")) {
00664 sscanf(value, "%lf", &vmu->volgain);
00665 } else if (!strcasecmp(var, "options")) {
00666 apply_options(vmu, value);
00667 }
00668 }
00669
00670 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
00671 {
00672 int res;
00673 if (!ast_strlen_zero(vmu->uniqueid)) {
00674 res = ast_update_realtime("voicemail", "uniqueid", vmu->uniqueid, "password", password, NULL);
00675 if (res > 0) {
00676 ast_copy_string(vmu->password, password, sizeof(vmu->password));
00677 res = 0;
00678 } else if (!res) {
00679 res = -1;
00680 }
00681 return res;
00682 }
00683 return -1;
00684 }
00685
00686 static void apply_options(struct ast_vm_user *vmu, const char *options)
00687 {
00688 char *stringp;
00689 char *s;
00690 char *var, *value;
00691 stringp = ast_strdupa(options);
00692 while ((s = strsep(&stringp, "|"))) {
00693 value = s;
00694 if ((var = strsep(&value, "=")) && value) {
00695 apply_option(vmu, var, value);
00696 }
00697 }
00698 }
00699
00700 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
00701 {
00702 struct ast_variable *tmp;
00703 tmp = var;
00704 while (tmp) {
00705 if (!strcasecmp(tmp->name, "vmsecret")) {
00706 ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
00707 } else if (!strcasecmp(tmp->name, "secret") || !strcasecmp(tmp->name, "password")) {
00708 if (ast_strlen_zero(retval->password))
00709 ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
00710 } else if (!strcasecmp(tmp->name, "uniqueid")) {
00711 ast_copy_string(retval->uniqueid, tmp->value, sizeof(retval->uniqueid));
00712 } else if (!strcasecmp(tmp->name, "pager")) {
00713 ast_copy_string(retval->pager, tmp->value, sizeof(retval->pager));
00714 } else if (!strcasecmp(tmp->name, "email")) {
00715 ast_copy_string(retval->email, tmp->value, sizeof(retval->email));
00716 } else if (!strcasecmp(tmp->name, "fullname")) {
00717 ast_copy_string(retval->fullname, tmp->value, sizeof(retval->fullname));
00718 } else if (!strcasecmp(tmp->name, "context")) {
00719 ast_copy_string(retval->context, tmp->value, sizeof(retval->context));
00720 #ifdef IMAP_STORAGE
00721 } else if (!strcasecmp(tmp->name, "imapuser")) {
00722 ast_copy_string(retval->imapuser, tmp->value, sizeof(retval->imapuser));
00723 } else if (!strcasecmp(tmp->name, "imappassword")) {
00724 ast_copy_string(retval->imappassword, tmp->value, sizeof(retval->imappassword));
00725 #endif
00726 } else
00727 apply_option(retval, tmp->name, tmp->value);
00728 tmp = tmp->next;
00729 }
00730 }
00731
00732 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
00733 {
00734 struct ast_variable *var;
00735 struct ast_vm_user *retval;
00736
00737 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
00738 if (!ivm)
00739 ast_set_flag(retval, VM_ALLOCED);
00740 else
00741 memset(retval, 0, sizeof(*retval));
00742 if (mailbox)
00743 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
00744 populate_defaults(retval);
00745 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
00746 var = ast_load_realtime("voicemail", "mailbox", mailbox, NULL);
00747 else
00748 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, NULL);
00749 if (var) {
00750 apply_options_full(retval, var);
00751 ast_variables_destroy(var);
00752 } else {
00753 if (!ivm)
00754 free(retval);
00755 retval = NULL;
00756 }
00757 }
00758 return retval;
00759 }
00760
00761 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
00762 {
00763
00764 struct ast_vm_user *vmu=NULL, *cur;
00765 AST_LIST_LOCK(&users);
00766
00767 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
00768 context = "default";
00769
00770 AST_LIST_TRAVERSE(&users, cur, list) {
00771 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
00772 break;
00773 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
00774 break;
00775 }
00776 if (cur) {
00777
00778 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
00779 memcpy(vmu, cur, sizeof(*vmu));
00780 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
00781 AST_LIST_NEXT(vmu, list) = NULL;
00782 }
00783 } else
00784 vmu = find_user_realtime(ivm, context, mailbox);
00785 AST_LIST_UNLOCK(&users);
00786 return vmu;
00787 }
00788
00789 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
00790 {
00791
00792 struct ast_vm_user *cur;
00793 int res = -1;
00794 AST_LIST_LOCK(&users);
00795 AST_LIST_TRAVERSE(&users, cur, list) {
00796 if ((!context || !strcasecmp(context, cur->context)) &&
00797 (!strcasecmp(mailbox, cur->mailbox)))
00798 break;
00799 }
00800 if (cur) {
00801 ast_copy_string(cur->password, newpass, sizeof(cur->password));
00802 res = 0;
00803 }
00804 AST_LIST_UNLOCK(&users);
00805 return res;
00806 }
00807
00808 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
00809 {
00810 struct ast_config *cfg=NULL;
00811 struct ast_variable *var=NULL;
00812 struct ast_category *cat=NULL;
00813 char *category=NULL, *value=NULL, *new=NULL;
00814 const char *tmp=NULL;
00815
00816 if (!change_password_realtime(vmu, newpassword))
00817 return;
00818
00819
00820 if ((cfg = ast_config_load_with_comments(VOICEMAIL_CONFIG))) {
00821 while ((category = ast_category_browse(cfg, category))) {
00822 if (!strcasecmp(category, vmu->context)) {
00823 tmp = ast_variable_retrieve(cfg, category, vmu->mailbox);
00824 if (!tmp) {
00825 ast_log(LOG_WARNING, "We could not find the mailbox.\n");
00826 break;
00827 }
00828 value = strstr(tmp,",");
00829 if (!value) {
00830 ast_log(LOG_WARNING, "variable has bad format.\n");
00831 break;
00832 }
00833 new = alloca((strlen(value)+strlen(newpassword)+1));
00834 sprintf(new,"%s%s", newpassword, value);
00835 if (!(cat = ast_category_get(cfg, category))) {
00836 ast_log(LOG_WARNING, "Failed to get category structure.\n");
00837 break;
00838 }
00839 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
00840 }
00841 }
00842
00843 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
00844 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
00845 config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
00846 }
00847 category = NULL;
00848 var = NULL;
00849
00850
00851 if ((cfg = ast_config_load_with_comments("users.conf"))) {
00852 if (option_debug > 3)
00853 ast_log(LOG_DEBUG, "we are looking for %s\n", vmu->mailbox);
00854 while ((category = ast_category_browse(cfg, category))) {
00855 if (option_debug > 3)
00856 ast_log(LOG_DEBUG, "users.conf: %s\n", category);
00857 if (!strcasecmp(category, vmu->mailbox)) {
00858 if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
00859 if (option_debug > 3)
00860 ast_log(LOG_DEBUG, "looks like we need to make vmsecret!\n");
00861 var = ast_variable_new("vmsecret", newpassword);
00862 }
00863 new = alloca(strlen(newpassword)+1);
00864 sprintf(new, "%s", newpassword);
00865 if (!(cat = ast_category_get(cfg, category))) {
00866 if (option_debug > 3)
00867 ast_log(LOG_DEBUG, "failed to get category!\n");
00868 break;
00869 }
00870 if (!var)
00871 ast_variable_update(cat, "vmsecret", new, NULL, 0);
00872 else
00873 ast_variable_append(cat, var);
00874 }
00875 }
00876
00877 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
00878 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
00879 config_text_file_save("users.conf", cfg, "AppVoicemail");
00880 }
00881 }
00882
00883 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
00884 {
00885 char buf[255];
00886 snprintf(buf,255,"%s %s %s %s",ext_pass_cmd,vmu->context,vmu->mailbox,newpassword);
00887 if (!ast_safe_system(buf)) {
00888 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
00889
00890 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
00891 }
00892 }
00893
00894 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
00895 {
00896 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
00897 }
00898
00899 static int make_file(char *dest, const int len, const char *dir, const int num)
00900 {
00901 return snprintf(dest, len, "%s/msg%04d", dir, num);
00902 }
00903
00904
00905 static FILE *vm_mkftemp(char *template)
00906 {
00907 FILE *p = NULL;
00908 int pfd = mkstemp(template);
00909 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
00910 if (pfd > -1) {
00911 p = fdopen(pfd, "w+");
00912 if (!p) {
00913 close(pfd);
00914 pfd = -1;
00915 }
00916 }
00917 return p;
00918 }
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
00929 {
00930 mode_t mode = VOICEMAIL_DIR_MODE;
00931
00932 if (!ast_strlen_zero(context)) {
00933 make_dir(dest, len, context, "", "");
00934 if (mkdir(dest, mode) && errno != EEXIST) {
00935 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
00936 return -1;
00937 }
00938 }
00939 if (!ast_strlen_zero(ext)) {
00940 make_dir(dest, len, context, ext, "");
00941 if (mkdir(dest, mode) && errno != EEXIST) {
00942 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
00943 return -1;
00944 }
00945 }
00946 if (!ast_strlen_zero(folder)) {
00947 make_dir(dest, len, context, ext, folder);
00948 if (mkdir(dest, mode) && errno != EEXIST) {
00949 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dest, strerror(errno));
00950 return -1;
00951 }
00952 }
00953 return 0;
00954 }
00955
00956 static char *mbox(int id)
00957 {
00958 static char *msgs[] = {
00959 "INBOX",
00960 "Old",
00961 "Work",
00962 "Family",
00963 "Friends",
00964 "Cust1",
00965 "Cust2",
00966 "Cust3",
00967 "Cust4",
00968 "Cust5",
00969 };
00970 return (id >= 0 && id < (sizeof(msgs)/sizeof(msgs[0]))) ? msgs[id] : "tmp";
00971 }
00972
00973 static void free_user(struct ast_vm_user *vmu)
00974 {
00975 if (ast_test_flag(vmu, VM_ALLOCED))
00976 free(vmu);
00977 }
00978
00979
00980
00981 #ifdef IMAP_STORAGE
00982 static void vm_imap_delete(int msgnum, struct ast_vm_user *vmu)
00983 {
00984 char arg[10];
00985 struct vm_state *vms;
00986 unsigned long messageNum;
00987
00988
00989 if (msgnum < 0) {
00990 return;
00991 }
00992
00993 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
00994 ast_log(LOG_WARNING, "Couldn't find a vm_state for mailbox %s. Unable to set \\DELETED flag for message %d\n", vmu->mailbox, msgnum);
00995 return;
00996 }
00997
00998
00999
01000 messageNum = vms->msgArray[msgnum];
01001 if (messageNum == 0) {
01002 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n",msgnum,messageNum);
01003 return;
01004 }
01005 if (option_debug > 2)
01006 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n",msgnum,messageNum);
01007
01008 snprintf (arg, sizeof(arg), "%lu",messageNum);
01009 mail_setflag (vms->mailstream,arg,"\\DELETED");
01010 }
01011
01012 static int imap_retrieve_file(const char *dir, const int msgnum, const struct ast_vm_user *vmu)
01013 {
01014 BODY *body;
01015 char *header_content;
01016 char *attachedfilefmt;
01017 const char *cid_num;
01018 const char *cid_name;
01019 const char *duration;
01020 const char *context;
01021 const char *category;
01022 const char *origtime;
01023 struct vm_state *vms;
01024 char text_file[PATH_MAX];
01025 FILE *text_file_ptr;
01026
01027
01028
01029
01030 if (msgnum < 0) {
01031 return 0;
01032 }
01033
01034
01035
01036
01037 if(!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01038
01039
01040
01041
01042
01043
01044
01045 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01046 }
01047
01048 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01049
01050
01051 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01052 return 0;
01053 }
01054
01055 if (option_debug > 2)
01056 ast_log (LOG_DEBUG,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01057 if (vms->msgArray[msgnum] == 0) {
01058 ast_log (LOG_WARNING,"Trying to access unknown message\n");
01059 return -1;
01060 }
01061
01062
01063 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01064
01065 if (ast_strlen_zero(header_content)) {
01066 ast_log (LOG_ERROR,"Could not fetch header for message number %ld\n",vms->msgArray[msgnum]);
01067 return -1;
01068 }
01069
01070 mail_fetchstructure (vms->mailstream,vms->msgArray[msgnum],&body);
01071
01072
01073 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01074 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01075 } else {
01076 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01077 return -1;
01078 }
01079
01080
01081
01082 strsep(&attachedfilefmt, ".");
01083 if (!attachedfilefmt) {
01084 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01085 return -1;
01086 }
01087
01088 save_body(body, vms, "2", attachedfilefmt);
01089
01090
01091 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01092
01093 if (!(text_file_ptr = fopen(text_file, "w"))) {
01094 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
01095 }
01096
01097 fprintf(text_file_ptr, "%s\n", "[message]");
01098
01099 cid_num = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:");
01100 cid_name = get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:");
01101 fprintf(text_file_ptr, "callerid=\"%s\" <%s>\n", S_OR(cid_name, ""), S_OR(cid_num, ""));
01102 context = get_header_by_tag(header_content, "X-Asterisk-VM-Context:");
01103 fprintf(text_file_ptr, "context=%s\n", S_OR(context, ""));
01104 origtime = get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:");
01105 fprintf(text_file_ptr, "origtime=%s\n", S_OR(origtime, ""));
01106 duration = get_header_by_tag(header_content, "X-Asterisk-VM-Duration:");
01107 fprintf(text_file_ptr, "duration=%s\n", S_OR(origtime, ""));
01108 category = get_header_by_tag(header_content, "X-Asterisk-VM-Category:");
01109 fprintf(text_file_ptr, "category=%s\n", S_OR(category, ""));
01110
01111 fclose(text_file_ptr);
01112 return 0;
01113 }
01114
01115 static int folder_int(const char *folder)
01116 {
01117
01118 if (!folder)
01119 return 0;
01120 if (!strcasecmp(folder, "INBOX"))
01121 return 0;
01122 else if (!strcasecmp(folder, "Old"))
01123 return 1;
01124 else if (!strcasecmp(folder, "Work"))
01125 return 2;
01126 else if (!strcasecmp(folder, "Family"))
01127 return 3;
01128 else if (!strcasecmp(folder, "Friends"))
01129 return 4;
01130 else if (!strcasecmp(folder, "Cust1"))
01131 return 5;
01132 else if (!strcasecmp(folder, "Cust2"))
01133 return 6;
01134 else if (!strcasecmp(folder, "Cust3"))
01135 return 7;
01136 else if (!strcasecmp(folder, "Cust4"))
01137 return 8;
01138 else if (!strcasecmp(folder, "Cust5"))
01139 return 9;
01140 else
01141 return 0;
01142 }
01143
01144 static int messagecount(const char *context, const char *mailbox, const char *folder)
01145 {
01146 SEARCHPGM *pgm;
01147 SEARCHHEADER *hdr;
01148
01149 struct ast_vm_user *vmu, vmus;
01150 struct vm_state *vms_p;
01151 int ret = 0;
01152 int fold = folder_int(folder);
01153
01154 if (ast_strlen_zero(mailbox))
01155 return 0;
01156
01157
01158
01159 vmu = find_user(&vmus, context, mailbox);
01160 if (!vmu) {
01161 ast_log (LOG_ERROR,"Couldn't find mailbox %s in context %s\n",mailbox,context);
01162 return -1;
01163 } else {
01164
01165 if (vmu->imapuser[0] == '\0') {
01166 ast_log (LOG_WARNING,"IMAP user not set for mailbox %s\n",vmu->mailbox);
01167 return -1;
01168 }
01169 }
01170
01171
01172 vms_p = get_vm_state_by_imapuser(vmu->imapuser,1);
01173 if (!vms_p) {
01174 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
01175 }
01176 if (vms_p) {
01177 if (option_debug > 2)
01178 ast_log (LOG_DEBUG,"Returning before search - user is logged in\n");
01179 if (fold == 0) {
01180 return vms_p->newmessages;
01181 }
01182 if (fold == 1) {
01183 return vms_p->oldmessages;
01184 }
01185 }
01186
01187
01188 vms_p = get_vm_state_by_imapuser(vmu->imapuser,0);
01189 if (!vms_p) {
01190 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
01191 }
01192
01193 if (!vms_p) {
01194 if (!(vms_p = create_vm_state_from_user(vmu))) {
01195 ast_log(LOG_WARNING, "Unable to allocate space for new vm_state!\n");
01196 return -1;
01197 }
01198 }
01199 ret = init_mailstream(vms_p, fold);
01200 if (!vms_p->mailstream) {
01201 ast_log (LOG_ERROR,"IMAP mailstream is NULL\n");
01202 return -1;
01203 }
01204 if (ret == 0) {
01205 pgm = mail_newsearchpgm ();
01206 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)mailbox);
01207 pgm->header = hdr;
01208 if (fold != 1) {
01209 pgm->unseen = 1;
01210 pgm->seen = 0;
01211 }
01212
01213
01214
01215 else {
01216 pgm->unseen = 0;
01217 pgm->seen = 1;
01218 }
01219 pgm->undeleted = 1;
01220 pgm->deleted = 0;
01221
01222 vms_p->vmArrayIndex = 0;
01223 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
01224 if (fold == 0)
01225 vms_p->newmessages = vms_p->vmArrayIndex;
01226 if (fold == 1)
01227 vms_p->oldmessages = vms_p->vmArrayIndex;
01228
01229 mail_free_searchpgm(&pgm);
01230 vms_p->updated = 0;
01231 return vms_p->vmArrayIndex;
01232 } else {
01233 mail_ping(vms_p->mailstream);
01234 }
01235 return 0;
01236 }
01237
01238 static int imap_store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms)
01239 {
01240 char *myserveremail = serveremail;
01241 char fn[PATH_MAX];
01242 char mailbox[256];
01243 char *stringp;
01244 FILE *p=NULL;
01245 char tmp[80] = "/tmp/astmail-XXXXXX";
01246 long len;
01247 void *buf;
01248 int tempcopy = 0;
01249 STRING str;
01250
01251
01252 if (msgnum < 0)
01253 return 0;
01254
01255
01256 fmt = ast_strdupa(fmt);
01257 stringp = fmt;
01258 strsep(&stringp, "|");
01259
01260 if (!ast_strlen_zero(vmu->serveremail))
01261 myserveremail = vmu->serveremail;
01262
01263 make_file(fn, sizeof(fn), dir, msgnum);
01264
01265 if (ast_strlen_zero(vmu->email)) {
01266
01267
01268
01269
01270 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
01271 tempcopy = 1;
01272 }
01273
01274 if (!strcmp(fmt, "wav49"))
01275 fmt = "WAV";
01276 if (option_debug > 2)
01277 ast_log(LOG_DEBUG, "Storing file '%s', format '%s'\n", fn, fmt);
01278
01279
01280 if ((p = vm_mkftemp(tmp)) == NULL) {
01281 ast_log(LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
01282 if (tempcopy)
01283 *(vmu->email) = '\0';
01284 return -1;
01285 } else {
01286 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), fn, fmt, duration, 1, chan, NULL, 1);
01287
01288 len = ftell(p);
01289 rewind(p);
01290 if ((buf = ast_malloc(len+1)) == NIL) {
01291 ast_log(LOG_ERROR, "Can't allocate %ld bytes to read message\n", len+1);
01292 fclose(p);
01293 return -1;
01294 }
01295 fread(buf, len, 1, p);
01296 ((char *)buf)[len] = '\0';
01297 INIT(&str, mail_string, buf, len);
01298 init_mailstream(vms, 0);
01299 imap_mailbox_name(mailbox, sizeof(mailbox), vms, 0, 1);
01300 if (!mail_append(vms->mailstream, mailbox, &str))
01301 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
01302 fclose(p);
01303 unlink(tmp);
01304 ast_free(buf);
01305 if (option_debug > 2)
01306 ast_log(LOG_DEBUG, "%s stored\n", fn);
01307
01308
01309
01310 messagecount(vmu->context, vmu->mailbox, "INBOX");
01311 }
01312 if (tempcopy)
01313 *(vmu->email) = '\0';
01314 return 0;
01315
01316 }
01317
01318 static int inboxcount(const char *mailbox_context, int *newmsgs, int *oldmsgs)
01319 {
01320 char tmp[PATH_MAX] = "";
01321 char *mailboxnc;
01322 char *context;
01323 char *mb;
01324 char *cur;
01325 if (newmsgs)
01326 *newmsgs = 0;
01327 if (oldmsgs)
01328 *oldmsgs = 0;
01329
01330 if (option_debug > 2)
01331 ast_log (LOG_DEBUG,"Mailbox is set to %s\n",mailbox_context);
01332
01333 if (ast_strlen_zero(mailbox_context))
01334 return 0;
01335
01336 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
01337 context = strchr(tmp, '@');
01338 if (strchr(mailbox_context, ',')) {
01339 int tmpnew, tmpold;
01340 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
01341 mb = tmp;
01342 while ((cur = strsep(&mb, ", "))) {
01343 if (!ast_strlen_zero(cur)) {
01344 if (inboxcount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
01345 return -1;
01346 else {
01347 if (newmsgs)
01348 *newmsgs += tmpnew;
01349 if (oldmsgs)
01350 *oldmsgs += tmpold;
01351 }
01352 }
01353 }
01354 return 0;
01355 }
01356 if (context) {
01357 *context = '\0';
01358 mailboxnc = tmp;
01359 context++;
01360 } else {
01361 context = "default";
01362 mailboxnc = (char *)mailbox_context;
01363 }
01364 if (newmsgs) {
01365 if ((*newmsgs = messagecount(context, mailboxnc, "INBOX")) < 0)
01366 return -1;
01367 }
01368 if (oldmsgs) {
01369 if ((*oldmsgs = messagecount(context, mailboxnc, "Old")) < 0)
01370 return -1;
01371 }
01372 return 0;
01373 }
01374
01375
01376 static int has_voicemail(const char *mailbox, const char *folder)
01377 {
01378 char tmp[256], *tmp2, *mbox, *context;
01379 ast_copy_string(tmp, mailbox, sizeof(tmp));
01380 tmp2 = tmp;
01381 if (strchr(tmp2, ',')) {
01382 while ((mbox = strsep(&tmp2, ","))) {
01383 if (!ast_strlen_zero(mbox)) {
01384 if (has_voicemail(mbox, folder))
01385 return 1;
01386 }
01387 }
01388 }
01389 if ((context= strchr(tmp, '@')))
01390 *context++ = '\0';
01391 else
01392 context = "default";
01393 return messagecount(context, tmp, folder) ? 1 : 0;
01394 }
01395
01396 static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir)
01397 {
01398 struct vm_state *sendvms = NULL, *destvms = NULL;
01399 char messagestring[10];
01400 if (msgnum >= recip->maxmsg) {
01401 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
01402 return -1;
01403 }
01404 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
01405 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
01406 return -1;
01407 }
01408 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
01409 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
01410 return -1;
01411 }
01412 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
01413 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(imbox)) == T))
01414 return 0;
01415 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
01416 return -1;
01417 }
01418
01419 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
01420 {
01421 char tmp[256], *t = tmp;
01422 size_t left = sizeof(tmp);
01423
01424 if (box == 1) {
01425 ast_copy_string(vms->curbox, mbox(0), sizeof(vms->curbox));
01426 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(1));
01427 } else {
01428 ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
01429 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
01430 }
01431
01432
01433 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
01434
01435
01436 if (!ast_strlen_zero(authuser))
01437 ast_build_string(&t, &left, "/authuser=%s", authuser);
01438
01439
01440 if (!ast_strlen_zero(imapflags))
01441 ast_build_string(&t, &left, "/%s", imapflags);
01442
01443
01444 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
01445
01446 if (box == 0 || box == 1)
01447 snprintf(spec, len, "%s%s", tmp, use_folder? imapfolder: "INBOX");
01448 else
01449 snprintf(spec, len, "%s%s%c%s", tmp, imapfolder, delimiter, mbox(box));
01450 }
01451
01452 static int init_mailstream(struct vm_state *vms, int box)
01453 {
01454 MAILSTREAM *stream = NIL;
01455 long debug;
01456 char tmp[256];
01457
01458 if (!vms) {
01459 ast_log (LOG_ERROR,"vm_state is NULL!\n");
01460 return -1;
01461 }
01462 if (option_debug > 2)
01463 ast_log (LOG_DEBUG,"vm_state user is:%s\n",vms->imapuser);
01464 if (vms->mailstream == NIL || !vms->mailstream) {
01465 if (option_debug)
01466 ast_log (LOG_DEBUG,"mailstream not set.\n");
01467 } else {
01468 stream = vms->mailstream;
01469 }
01470
01471 debug = NIL;
01472
01473 if (delimiter == '\0') {
01474 char *cp;
01475 #ifdef USE_SYSTEM_IMAP
01476 #include <imap/linkage.c>
01477 #elif defined(USE_SYSTEM_CCLIENT)
01478 #include <c-client/linkage.c>
01479 #else
01480 #include "linkage.c"
01481 #endif
01482
01483 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
01484 ast_mutex_lock(&vms->lock);
01485 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
01486 ast_mutex_unlock(&vms->lock);
01487 if (stream == NIL) {
01488 ast_log (LOG_ERROR, "Can't connect to imap server %s\n", tmp);
01489 return -1;
01490 }
01491 get_mailbox_delimiter(stream);
01492
01493 for (cp = imapfolder; *cp; cp++)
01494 if (*cp == '/')
01495 *cp = delimiter;
01496 }
01497
01498 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
01499 if (option_debug > 2)
01500 ast_log (LOG_DEBUG,"Before mail_open, server: %s, box:%d\n", tmp, box);
01501 ast_mutex_lock(&vms->lock);
01502 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
01503 ast_mutex_unlock(&vms->lock);
01504 if (vms->mailstream == NIL) {
01505 return -1;
01506 } else {
01507 return 0;
01508 }
01509 }
01510
01511 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
01512 {
01513 SEARCHPGM *pgm;
01514 SEARCHHEADER *hdr;
01515 int ret;
01516
01517 ast_copy_string(vms->imapuser,vmu->imapuser, sizeof(vms->imapuser));
01518 if (option_debug > 2)
01519 ast_log(LOG_DEBUG,"Before init_mailstream, user is %s\n",vmu->imapuser);
01520 ret = init_mailstream(vms, box);
01521 if (ret != 0 || !vms->mailstream) {
01522 ast_log (LOG_ERROR,"Could not initialize mailstream\n");
01523 return -1;
01524 }
01525
01526 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
01527
01528
01529 if (box == 0) {
01530 if (option_debug > 2)
01531 ast_log(LOG_DEBUG, "Mailbox name set to: %s, about to check quotas\n", mbox(box));
01532 check_quota(vms,(char *)mbox(box));
01533 }
01534
01535 pgm = mail_newsearchpgm();
01536
01537
01538 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", vmu->mailbox);
01539 pgm->header = hdr;
01540 pgm->deleted = 0;
01541 pgm->undeleted = 1;
01542
01543
01544 if (box == 0) {
01545 pgm->unseen = 1;
01546 pgm->seen = 0;
01547 } else if (box == 1) {
01548 pgm->seen = 1;
01549 pgm->unseen = 0;
01550 }
01551
01552 vms->vmArrayIndex = 0;
01553 if (option_debug > 2)
01554 ast_log(LOG_DEBUG,"Before mail_search_full, user is %s\n",vmu->imapuser);
01555 mail_search_full (vms->mailstream, NULL, pgm, NIL);
01556
01557 vms->lastmsg = vms->vmArrayIndex - 1;
01558
01559 mail_free_searchpgm(&pgm);
01560 return 0;
01561 }
01562
01563 static void write_file(char *filename, char *buffer, unsigned long len)
01564 {
01565 FILE *output;
01566
01567 output = fopen (filename, "w");
01568 fwrite (buffer, len, 1, output);
01569 fclose (output);
01570 }
01571
01572 void mm_searched(MAILSTREAM *stream, unsigned long number)
01573 {
01574 struct vm_state *vms;
01575 char *mailbox;
01576 char *user;
01577 mailbox = stream->mailbox;
01578 user = get_user_by_mailbox(mailbox);
01579 vms = get_vm_state_by_imapuser(user,2);
01580 if (vms) {
01581 if (option_debug > 2)
01582 ast_log (LOG_DEBUG, "saving mailbox message number %lu as message %d. Interactive set to %d\n",number,vms->vmArrayIndex,vms->interactive);
01583 vms->msgArray[vms->vmArrayIndex++] = number;
01584 } else {
01585 ast_log (LOG_ERROR, "No state found.\n");
01586 }
01587 }
01588
01589 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
01590 {
01591 struct ast_variable *var;
01592 struct ast_vm_user *vmu;
01593
01594 vmu = ast_calloc(1, sizeof *vmu);
01595 if (!vmu)
01596 return NULL;
01597 ast_set_flag(vmu, VM_ALLOCED);
01598 populate_defaults(vmu);
01599
01600 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
01601 if (var) {
01602 apply_options_full(vmu, var);
01603 ast_variables_destroy(var);
01604 return vmu;
01605 } else {
01606 free(vmu);
01607 return NULL;
01608 }
01609 }
01610
01611
01612
01613 void mm_exists(MAILSTREAM * stream, unsigned long number)
01614 {
01615
01616 if (option_debug > 3)
01617 ast_log (LOG_DEBUG, "Entering EXISTS callback for message %ld\n", number);
01618 if (number == 0) return;
01619 set_update(stream);
01620 }
01621
01622
01623 void mm_expunged(MAILSTREAM * stream, unsigned long number)
01624 {
01625
01626 if (option_debug > 3)
01627 ast_log (LOG_DEBUG, "Entering EXPUNGE callback for message %ld\n", number);
01628 if (number == 0) return;
01629 set_update(stream);
01630 }
01631
01632
01633 void mm_flags(MAILSTREAM * stream, unsigned long number)
01634 {
01635
01636 if (option_debug > 3)
01637 ast_log (LOG_DEBUG, "Entering FLAGS callback for message %ld\n", number);
01638 if (number == 0) return;
01639 set_update(stream);
01640 }
01641
01642
01643 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
01644 {
01645 mm_log (string, errflg);
01646 }
01647
01648
01649 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
01650 {
01651 if (delimiter == '\0') {
01652 delimiter = delim;
01653 }
01654 if (option_debug > 4) {
01655 ast_log(LOG_DEBUG, "Delimiter set to %c and mailbox %s\n",delim, mailbox);
01656 if (attributes & LATT_NOINFERIORS)
01657 ast_log(LOG_DEBUG, "no inferiors\n");
01658 if (attributes & LATT_NOSELECT)
01659 ast_log(LOG_DEBUG, "no select\n");
01660 if (attributes & LATT_MARKED)
01661 ast_log(LOG_DEBUG, "marked\n");
01662 if (attributes & LATT_UNMARKED)
01663 ast_log(LOG_DEBUG, "unmarked\n");
01664 }
01665 }
01666
01667
01668 void mm_lsub(MAILSTREAM * stream, int delimiter, char *mailbox, long attributes)
01669 {
01670 if (option_debug > 4) {
01671 ast_log(LOG_DEBUG, "Delimiter set to %c and mailbox %s\n",delimiter, mailbox);
01672 if (attributes & LATT_NOINFERIORS)
01673 ast_log(LOG_DEBUG, "no inferiors\n");
01674 if (attributes & LATT_NOSELECT)
01675 ast_log(LOG_DEBUG, "no select\n");
01676 if (attributes & LATT_MARKED)
01677 ast_log(LOG_DEBUG, "marked\n");
01678 if (attributes & LATT_UNMARKED)
01679 ast_log(LOG_DEBUG, "unmarked\n");
01680 }
01681 }
01682
01683
01684 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
01685 {
01686 ast_log (LOG_NOTICE," Mailbox %s", mailbox);
01687 if (status->flags & SA_MESSAGES)
01688 ast_log (LOG_NOTICE,", %lu messages", status->messages);
01689 if (status->flags & SA_RECENT)
01690 ast_log (LOG_NOTICE,", %lu recent", status->recent);
01691 if (status->flags & SA_UNSEEN)
01692 ast_log (LOG_NOTICE,", %lu unseen", status->unseen);
01693 if (status->flags & SA_UIDVALIDITY)
01694 ast_log (LOG_NOTICE,", %lu UID validity", status->uidvalidity);
01695 if (status->flags & SA_UIDNEXT)
01696 ast_log (LOG_NOTICE,", %lu next UID", status->uidnext);
01697 ast_log (LOG_NOTICE,"\n");
01698 }
01699
01700
01701 void mm_log(char *string, long errflg)
01702 {
01703 switch ((short) errflg) {
01704 case NIL:
01705 if (option_debug)
01706 ast_log(LOG_DEBUG,"IMAP Info: %s\n", string);
01707 break;
01708 case PARSE:
01709 case WARN:
01710 ast_log (LOG_WARNING,"IMAP Warning: %s\n", string);
01711 break;
01712 case ERROR:
01713 ast_log (LOG_ERROR,"IMAP Error: %s\n", string);
01714 break;
01715 }
01716 }
01717
01718
01719 void mm_dlog(char *string)
01720 {
01721 ast_log (LOG_NOTICE, "%s\n", string);
01722 }
01723
01724
01725 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
01726 {
01727 struct ast_vm_user *vmu;
01728
01729 if (option_debug > 3)
01730 ast_log(LOG_DEBUG, "Entering callback mm_login\n");
01731
01732 ast_copy_string(user, mb->user, MAILTMPLEN);
01733
01734
01735 if (!ast_strlen_zero(authpassword)) {
01736 ast_copy_string(pwd, authpassword, MAILTMPLEN);
01737 } else {
01738 AST_LIST_TRAVERSE(&users, vmu, list) {
01739 if (!strcasecmp(mb->user, vmu->imapuser)) {
01740 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
01741 break;
01742 }
01743 }
01744 if (!vmu) {
01745 if ((vmu = find_user_realtime_imapuser(mb->user))) {
01746 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
01747 free_user(vmu);
01748 }
01749 }
01750 }
01751 }
01752
01753
01754 void mm_critical(MAILSTREAM * stream)
01755 {
01756 }
01757
01758
01759 void mm_nocritical(MAILSTREAM * stream)
01760 {
01761 }
01762
01763
01764 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
01765 {
01766 kill (getpid (), SIGSTOP);
01767 return NIL;
01768 }
01769
01770
01771 void mm_fatal(char *string)
01772 {
01773 ast_log(LOG_ERROR,"IMAP access FATAL error: %s\n", string);
01774 }
01775
01776
01777 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
01778 {
01779 struct vm_state *vms;
01780 char *mailbox;
01781 char *user;
01782 unsigned long usage = 0;
01783 unsigned long limit = 0;
01784
01785 while (pquota) {
01786 usage = pquota->usage;
01787 limit = pquota->limit;
01788 pquota = pquota->next;
01789 }
01790
01791 mailbox = stream->mailbox;
01792 user = get_user_by_mailbox(mailbox);
01793 vms = get_vm_state_by_imapuser(user,2);
01794 if (vms) {
01795 if (option_debug > 2)
01796 ast_log (LOG_DEBUG, "User %s usage is %lu, limit is %lu\n",user,usage,limit);
01797 vms->quota_usage = usage;
01798 vms->quota_limit = limit;
01799 } else {
01800 ast_log (LOG_ERROR, "No state found.\n");
01801 }
01802 }
01803
01804 static char *get_header_by_tag(char *header, char *tag)
01805 {
01806 char *start;
01807 int taglen;
01808 char *eol_pnt;
01809
01810 if (!header || !tag)
01811 return NULL;
01812
01813 taglen = strlen(tag) + 1;
01814 if (taglen < 1)
01815 return NULL;
01816
01817 start = strstr(header, tag);
01818 if (!start)
01819 return NULL;
01820
01821 ast_mutex_lock(&imaptemp_lock);
01822 ast_copy_string(imaptemp, start+taglen, sizeof(imaptemp));
01823 ast_mutex_unlock(&imaptemp_lock);
01824 if ((eol_pnt = strchr(imaptemp,'\r')) || (eol_pnt = strchr(imaptemp,'\n')))
01825 *eol_pnt = '\0';
01826 return imaptemp;
01827 }
01828
01829 static char *get_user_by_mailbox(char *mailbox)
01830 {
01831 char *start, *quote;
01832 char *eol_pnt;
01833
01834 if (!mailbox)
01835 return NULL;
01836
01837 start = strstr(mailbox,"/user=");
01838 if (!start)
01839 return NULL;
01840
01841 ast_mutex_lock(&imaptemp_lock);
01842 ast_copy_string(imaptemp, start+6, sizeof(imaptemp));
01843 ast_mutex_unlock(&imaptemp_lock);
01844
01845 quote = strchr(imaptemp,'\"');
01846 if (!quote) {
01847 eol_pnt = strchr(imaptemp,'/');
01848 if (!eol_pnt) {
01849 eol_pnt = strchr(imaptemp,'}');
01850 }
01851 *eol_pnt = '\0';
01852 return imaptemp;
01853 } else {
01854 eol_pnt = strchr(imaptemp+1,'\"');
01855 *eol_pnt = '\0';
01856 return imaptemp+1;
01857 }
01858 }
01859
01860 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
01861 {
01862 struct vm_state *vms_p;
01863
01864 if (option_debug > 4)
01865 ast_log(LOG_DEBUG,"Adding new vmstate for %s\n",vmu->imapuser);
01866 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
01867 return NULL;
01868 ast_copy_string(vms_p->imapuser,vmu->imapuser, sizeof(vms_p->imapuser));
01869 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
01870 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
01871 vms_p->mailstream = NIL;
01872 if (option_debug > 4)
01873 ast_log(LOG_DEBUG,"Copied %s to %s\n",vmu->imapuser,vms_p->imapuser);
01874 vms_p->updated = 1;
01875
01876 ast_copy_string(vms_p->curbox, mbox(0), sizeof(vms_p->curbox));
01877 init_vm_state(vms_p);
01878 vmstate_insert(vms_p);
01879 return vms_p;
01880 }
01881
01882 static struct vm_state *get_vm_state_by_imapuser(char *user, int interactive)
01883 {
01884 struct vmstate *vlist = NULL;
01885
01886 ast_mutex_lock(&vmstate_lock);
01887 vlist = vmstates;
01888 while (vlist) {
01889 if (vlist->vms) {
01890 if (vlist->vms->imapuser) {
01891 if (!strcmp(vlist->vms->imapuser,user)) {
01892 if (interactive == 2) {
01893 ast_mutex_unlock(&vmstate_lock);
01894 return vlist->vms;
01895 } else if (vlist->vms->interactive == interactive) {
01896 ast_mutex_unlock(&vmstate_lock);
01897 return vlist->vms;
01898 }
01899 }
01900 } else {
01901 if (option_debug > 2)
01902 ast_log(LOG_DEBUG, " error: imapuser is NULL for %s\n",user);
01903 }
01904 } else {
01905 if (option_debug > 2)
01906 ast_log(LOG_DEBUG, " error: vms is NULL for %s\n",user);
01907 }
01908 vlist = vlist->next;
01909 }
01910 ast_mutex_unlock(&vmstate_lock);
01911 if (option_debug > 2)
01912 ast_log(LOG_DEBUG, "%s not found in vmstates\n",user);
01913 return NULL;
01914 }
01915
01916 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
01917 {
01918 struct vmstate *vlist = NULL;
01919 const char *local_context = S_OR(context, "default");
01920
01921 ast_mutex_lock(&vmstate_lock);
01922 vlist = vmstates;
01923 if (option_debug > 2)
01924 ast_log(LOG_DEBUG, "Mailbox set to %s\n",mailbox);
01925 while (vlist) {
01926 if (vlist->vms) {
01927 if (vlist->vms->username && vlist->vms->context) {
01928 if (option_debug > 2)
01929 ast_log(LOG_DEBUG, " comparing mailbox %s (i=%d) to vmstate mailbox %s (i=%d)\n",mailbox,interactive,vlist->vms->username,vlist->vms->interactive);
01930 if (!strcmp(vlist->vms->username,mailbox) && !(strcmp(vlist->vms->context, local_context)) && vlist->vms->interactive == interactive) {
01931 if (option_debug > 2)
01932 ast_log(LOG_DEBUG, " Found it!\n");
01933 ast_mutex_unlock(&vmstate_lock);
01934 return vlist->vms;
01935 }
01936 } else {
01937 if (option_debug > 2)
01938 ast_log(LOG_DEBUG, " error: username or context is NULL for %s\n",mailbox);
01939 }
01940 } else {
01941 if (option_debug > 2)
01942 ast_log(LOG_DEBUG, " error: vms is NULL for %s\n",mailbox);
01943 }
01944 vlist = vlist->next;
01945 }
01946 ast_mutex_unlock(&vmstate_lock);
01947 if (option_debug > 2)
01948 ast_log(LOG_DEBUG, "%s not found in vmstates\n",mailbox);
01949 return NULL;
01950 }
01951
01952 static void vmstate_insert(struct vm_state *vms)
01953 {
01954 struct vmstate *v;
01955 struct vm_state *altvms;
01956
01957
01958
01959
01960 if (vms->interactive == 1) {
01961 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
01962 if (altvms) {
01963 if (option_debug > 2)
01964 ast_log(LOG_DEBUG, "Duplicate mailbox %s, copying message info...\n",vms->username);
01965 vms->newmessages = altvms->newmessages;
01966 vms->oldmessages = altvms->oldmessages;
01967
01968 copy_msgArray(vms, altvms);
01969 vms->vmArrayIndex = altvms->vmArrayIndex;
01970 vms->lastmsg = altvms->lastmsg;
01971 vms->curmsg = altvms->curmsg;
01972
01973 vms->persist_vms = altvms;
01974
01975 vms->mailstream = altvms->mailstream;
01976
01977 }
01978 }
01979
01980 v = (struct vmstate *)malloc(sizeof(struct vmstate));
01981 if (!v) {
01982 ast_log(LOG_ERROR, "Out of memory\n");
01983 }
01984 if (option_debug > 2)
01985 ast_log(LOG_DEBUG, "Inserting vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username);
01986 ast_mutex_lock(&vmstate_lock);
01987 v->vms = vms;
01988 v->next = vmstates;
01989 vmstates = v;
01990 ast_mutex_unlock(&vmstate_lock);
01991 }
01992
01993 static void vmstate_delete(struct vm_state *vms)
01994 {
01995 struct vmstate *vc, *vf = NULL, *vl = NULL;
01996 struct vm_state *altvms;
01997
01998
01999
02000 if (vms->interactive == 1) {
02001 altvms = vms->persist_vms;
02002 if (altvms) {
02003 if (option_debug > 2)
02004 ast_log(LOG_DEBUG, "Duplicate mailbox %s, copying message info...\n",vms->username);
02005 altvms->newmessages = vms->newmessages;
02006 altvms->oldmessages = vms->oldmessages;
02007 altvms->updated = 1;
02008 }
02009 }
02010
02011 ast_mutex_lock(&vmstate_lock);
02012 vc = vmstates;
02013 if (option_debug > 2)
02014 ast_log(LOG_DEBUG, "Removing vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username);
02015 while (vc) {
02016 if (vc->vms == vms) {
02017 vf = vc;
02018 if (vl)
02019 vl->next = vc->next;
02020 else
02021 vmstates = vc->next;
02022 break;
02023 }
02024 vl = vc;
02025 vc = vc->next;
02026 }
02027 if (!vf) {
02028 ast_log(LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n",vms->imapuser,vms->username);
02029 } else {
02030 ast_mutex_destroy(&vf->vms->lock);
02031 free(vf);
02032 }
02033 ast_mutex_unlock(&vmstate_lock);
02034 }
02035
02036 static void set_update(MAILSTREAM * stream)
02037 {
02038 struct vm_state *vms;
02039 char *mailbox;
02040 char *user;
02041
02042 mailbox = stream->mailbox;
02043 user = get_user_by_mailbox(mailbox);
02044 vms = get_vm_state_by_imapuser(user, 0);
02045 if (vms) {
02046 if (option_debug > 2)
02047 ast_log (LOG_DEBUG, "User %s mailbox set for update.\n",user);
02048 vms->updated = 1;
02049 } else {
02050 if (option_debug > 2)
02051 ast_log (LOG_WARNING, "User %s mailbox not found for update.\n",user);
02052 }
02053 }
02054
02055 static void init_vm_state(struct vm_state *vms)
02056 {
02057 int x;
02058 vms->vmArrayIndex = 0;
02059 for (x = 0; x < 256; x++) {
02060 vms->msgArray[x] = 0;
02061 }
02062 ast_mutex_init(&vms->lock);
02063 }
02064
02065 static void copy_msgArray(struct vm_state *dst, struct vm_state *src)
02066 {
02067 int x;
02068 for (x = 0; x<256; x++) {
02069 dst->msgArray[x] = src->msgArray[x];
02070 }
02071 }
02072
02073 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format)
02074 {
02075 char *body_content;
02076 char *body_decoded;
02077 unsigned long len;
02078 unsigned long newlen;
02079 char filename[256];
02080
02081 if (!body || body == NIL)
02082 return -1;
02083 body_content = mail_fetchbody (vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
02084 if (body_content != NIL) {
02085 snprintf(filename, sizeof(filename), "%s.%s", vms->fn, format);
02086
02087 body_decoded = rfc822_base64 ((unsigned char *)body_content, len, &newlen);
02088 write_file (filename, (char *) body_decoded, newlen);
02089 }
02090 return 0;
02091 }
02092
02093
02094 static void get_mailbox_delimiter(MAILSTREAM *stream) {
02095 char tmp[50];
02096 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
02097 mail_list(stream, tmp, "*");
02098 }
02099
02100
02101 static void check_quota(struct vm_state *vms, char *mailbox) {
02102 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
02103 if (option_debug > 2)
02104 ast_log(LOG_DEBUG, "Mailbox name set to: %s, about to check quotas\n", mailbox);
02105 if (vms && vms->mailstream != NULL) {
02106 imap_getquotaroot(vms->mailstream, mailbox);
02107 } else {
02108 ast_log(LOG_WARNING,"Mailstream not available for mailbox: %s\n",mailbox);
02109 }
02110 }
02111 #endif
02112
02113
02114
02115
02116 static int vm_lock_path(const char *path)
02117 {
02118 switch (ast_lock_path(path)) {
02119 case AST_LOCK_TIMEOUT:
02120 return -1;
02121 default:
02122 return 0;
02123 }
02124 }
02125
02126
02127 #ifdef ODBC_STORAGE
02128 struct generic_prepare_struct {
02129 char *sql;
02130 int argc;
02131 char **argv;
02132 };
02133
02134 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
02135 {
02136 struct generic_prepare_struct *gps = data;
02137 int res, i;
02138 SQLHSTMT stmt;
02139
02140 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
02141 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02142 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
02143 return NULL;
02144 }
02145 res = SQLPrepare(stmt, (unsigned char *)gps->sql, SQL_NTS);
02146 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02147 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
02148 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02149 return NULL;
02150 }
02151 for (i = 0; i < gps->argc; i++)
02152 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
02153
02154 return stmt;
02155 }
02156
02157 static int retrieve_file(char *dir, int msgnum)
02158 {
02159 int x = 0;
02160 int res;
02161 int fd=-1;
02162 size_t fdlen = 0;
02163 void *fdm = MAP_FAILED;
02164 SQLSMALLINT colcount=0;
02165 SQLHSTMT stmt;
02166 char sql[PATH_MAX];
02167 char fmt[80]="";
02168 char *c;
02169 char coltitle[256];
02170 SQLSMALLINT collen;
02171 SQLSMALLINT datatype;
02172 SQLSMALLINT decimaldigits;
02173 SQLSMALLINT nullable;
02174 SQLULEN colsize;
02175 SQLLEN colsize2;
02176 FILE *f=NULL;
02177 char rowdata[80];
02178 char fn[PATH_MAX];
02179 char full_fn[PATH_MAX];
02180 char msgnums[80];
02181 char *argv[] = { dir, msgnums };
02182 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
02183
02184 struct odbc_obj *obj;
02185 obj = ast_odbc_request_obj(odbc_database, 0);
02186 if (obj) {
02187 ast_copy_string(fmt, vmfmts, sizeof(fmt));
02188 c = strchr(fmt, '|');
02189 if (c)
02190 *c = '\0';
02191 if (!strcasecmp(fmt, "wav49"))
02192 strcpy(fmt, "WAV");
02193 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
02194 if (msgnum > -1)
02195 make_file(fn, sizeof(fn), dir, msgnum);
02196 else
02197 ast_copy_string(fn, dir, sizeof(fn));
02198 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
02199
02200 if (!(f = fopen(full_fn, "w+"))) {
02201 ast_log(LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
02202 goto yuck;
02203 }
02204
02205 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
02206 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?",odbc_table);
02207 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02208 if (!stmt) {
02209 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02210 ast_odbc_release_obj(obj);
02211 goto yuck;
02212 }
02213 res = SQLFetch(stmt);
02214 if (res == SQL_NO_DATA) {
02215 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02216 ast_odbc_release_obj(obj);
02217 goto yuck;
02218 }
02219 else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02220 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02221 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02222 ast_odbc_release_obj(obj);
02223 goto yuck;
02224 }
02225 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, 0770);
02226 if (fd < 0) {
02227 ast_log(LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
02228 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02229 ast_odbc_release_obj(obj);
02230 goto yuck;
02231 }
02232 res = SQLNumResultCols(stmt, &colcount);
02233 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02234 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
02235 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02236 ast_odbc_release_obj(obj);
02237 goto yuck;
02238 }
02239 if (f)
02240 fprintf(f, "[message]\n");
02241 for (x=0;x<colcount;x++) {
02242 rowdata[0] = '\0';
02243 collen = sizeof(coltitle);
02244 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
02245 &datatype, &colsize, &decimaldigits, &nullable);
02246 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02247 ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
02248 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02249 ast_odbc_release_obj(obj);
02250 goto yuck;
02251 }
02252 if (!strcasecmp(coltitle, "recording")) {
02253 off_t offset;
02254 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
02255 fdlen = colsize2;
02256 if (fd > -1) {
02257 char tmp[1]="";
02258 lseek(fd, fdlen - 1, SEEK_SET);
02259 if (write(fd, tmp, 1) != 1) {
02260 close(fd);
02261 fd = -1;
02262 continue;
02263 }
02264
02265 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
02266 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
02267 ast_log(LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
02268 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02269 ast_odbc_release_obj(obj);
02270 goto yuck;
02271 } else {
02272 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
02273 munmap(fdm, CHUNKSIZE);
02274 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02275 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02276 unlink(full_fn);
02277 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02278 ast_odbc_release_obj(obj);
02279 goto yuck;
02280 }
02281 }
02282 }
02283 truncate(full_fn, fdlen);
02284 }
02285 } else {
02286 SQLLEN ind;
02287 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &ind);
02288 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02289 SQLINTEGER nativeerror = 0;
02290 SQLSMALLINT diagbytes = 0;
02291 unsigned char state[10], diagnostic[256];
02292 SQLGetDiagRec(SQL_HANDLE_STMT, stmt, 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
02293 ast_log(LOG_WARNING, "SQL Get Data error: %s: %s!\n[%s]\n\n", state, diagnostic, sql);
02294 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02295 ast_odbc_release_obj(obj);
02296 goto yuck;
02297 }
02298 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
02299 fprintf(f, "%s=%s\n", coltitle, rowdata);
02300 }
02301 }
02302 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02303 ast_odbc_release_obj(obj);
02304 } else
02305 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02306 yuck:
02307 if (f)
02308 fclose(f);
02309 if (fd > -1)
02310 close(fd);
02311 return x - 1;
02312 }
02313
02314 static int last_message_index(struct ast_vm_user *vmu, char *dir)
02315 {
02316 int x = 0;
02317 int res;
02318 SQLHSTMT stmt;
02319 char sql[PATH_MAX];
02320 char rowdata[20];
02321 char *argv[] = { dir };
02322 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
02323
02324 struct odbc_obj *obj;
02325 obj = ast_odbc_request_obj(odbc_database, 0);
02326 if (obj) {
02327 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?",odbc_table);
02328 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02329 if (!stmt) {
02330 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02331 ast_odbc_release_obj(obj);
02332 goto yuck;
02333 }
02334 res = SQLFetch(stmt);
02335 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02336 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02337 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02338 ast_odbc_release_obj(obj);
02339 goto yuck;
02340 }
02341 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
02342 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02343 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02344 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02345 ast_odbc_release_obj(obj);
02346 goto yuck;
02347 }
02348 if (sscanf(rowdata, "%d", &x) != 1)
02349 ast_log(LOG_WARNING, "Failed to read message count!\n");
02350 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02351 ast_odbc_release_obj(obj);
02352 } else
02353 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02354 yuck:
02355 return x - 1;
02356 }
02357
02358 static int message_exists(char *dir, int msgnum)
02359 {
02360 int x = 0;
02361 int res;
02362 SQLHSTMT stmt;
02363 char sql[PATH_MAX];
02364 char rowdata[20];
02365 char msgnums[20];
02366 char *argv[] = { dir, msgnums };
02367 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
02368
02369 struct odbc_obj *obj;
02370 obj = ast_odbc_request_obj(odbc_database, 0);
02371 if (obj) {
02372 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
02373 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?",odbc_table);
02374 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02375 if (!stmt) {
02376 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02377 ast_odbc_release_obj(obj);
02378 goto yuck;
02379 }
02380 res = SQLFetch(stmt);
02381 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02382 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02383 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02384 ast_odbc_release_obj(obj);
02385 goto yuck;
02386 }
02387 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
02388 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02389 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
02390 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02391 ast_odbc_release_obj(obj);
02392 goto yuck;
02393 }
02394 if (sscanf(rowdata, "%d", &x) != 1)
02395 ast_log(LOG_WARNING, "Failed to read message count!\n");
02396 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02397 ast_odbc_release_obj(obj);
02398 } else
02399 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02400 yuck:
02401 return x;
02402 }
02403
02404 static int count_messages(struct ast_vm_user *vmu, char *dir)
02405 {
02406 return last_message_index(vmu, dir) + 1;
02407 }
02408
02409 static void delete_file(char *sdir, int smsg)
02410 {
02411 SQLHSTMT stmt;
02412 char sql[PATH_MAX];
02413 char msgnums[20];
02414 char *argv[] = { sdir, msgnums };
02415 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
02416
02417 struct odbc_obj *obj;
02418 obj = ast_odbc_request_obj(odbc_database, 0);
02419 if (obj) {
02420 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
02421 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?",odbc_table);
02422 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02423 if (!stmt)
02424 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02425 else
02426 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02427 ast_odbc_release_obj(obj);
02428 } else
02429 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02430 return;
02431 }
02432
02433 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
02434 {
02435 SQLHSTMT stmt;
02436 char sql[512];
02437 char msgnums[20];
02438 char msgnumd[20];
02439 struct odbc_obj *obj;
02440 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
02441 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
02442
02443 delete_file(ddir, dmsg);
02444 obj = ast_odbc_request_obj(odbc_database, 0);
02445 if (obj) {
02446 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
02447 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
02448 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, context, macrocontext, callerid, origtime, duration, recording, mailboxuser, mailboxcontext) SELECT ?,?,context,macrocontext,callerid,origtime,duration,recording,?,? FROM %s WHERE dir=? AND msgnum=?",odbc_table,odbc_table);
02449 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02450 if (!stmt)
02451 ast_log(LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
02452 else
02453 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02454 ast_odbc_release_obj(obj);
02455 } else
02456 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02457 return;
02458 }
02459
02460 struct insert_cb_struct {
02461 char *dir;
02462 char *msgnum;
02463 void *recording;
02464 size_t recordinglen;
02465 SQLLEN indlen;
02466 const char *context;
02467 const char *macrocontext;
02468 const char *callerid;
02469 const char *origtime;
02470 const char *duration;
02471 char *mailboxuser;
02472 char *mailboxcontext;
02473 const char *category;
02474 char *sql;
02475 };
02476
02477 static SQLHSTMT insert_cb(struct odbc_obj *obj, void *vd)
02478 {
02479 struct insert_cb_struct *d = vd;
02480 int res;
02481 SQLHSTMT stmt;
02482
02483 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
02484 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02485 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
02486 return NULL;
02487 }
02488
02489 res = SQLPrepare(stmt, (unsigned char *)d->sql, SQL_NTS);
02490 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02491 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", d->sql);
02492 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02493 return NULL;
02494 }
02495
02496 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->dir), 0, (void *)d->dir, 0, NULL);
02497 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->msgnum), 0, (void *)d->msgnum, 0, NULL);
02498 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, d->recordinglen, 0, (void *)d->recording, 0, &d->indlen);
02499 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->context), 0, (void *)d->context, 0, NULL);
02500 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->macrocontext), 0, (void *)d->macrocontext, 0, NULL);
02501 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->callerid), 0, (void *)d->callerid, 0, NULL);
02502 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->origtime), 0, (void *)d->origtime, 0, NULL);
02503 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->duration), 0, (void *)d->duration, 0, NULL);
02504 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->mailboxuser), 0, (void *)d->mailboxuser, 0, NULL);
02505 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->mailboxcontext), 0, (void *)d->mailboxcontext, 0, NULL);
02506 if (!ast_strlen_zero(d->category)) {
02507 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(d->category), 0, (void *)d->category, 0, NULL);
02508 }
02509
02510 return stmt;
02511 }
02512
02513 static int store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum)
02514 {
02515 int x = 0;
02516 int fd = -1;
02517 void *fdm = MAP_FAILED;
02518 size_t fdlen = -1;
02519 SQLHSTMT stmt;
02520 char sql[PATH_MAX];
02521 char msgnums[20];
02522 char fn[PATH_MAX];
02523 char full_fn[PATH_MAX];
02524 char fmt[80]="";
02525 char *c;
02526 struct insert_cb_struct d = {
02527 .dir = dir,
02528 .msgnum = msgnums,
02529 .context = "",
02530 .macrocontext = "",
02531 .callerid = "",
02532 .origtime = "",
02533 .duration = "",
02534 .mailboxuser = mailboxuser,
02535 .mailboxcontext = mailboxcontext,
02536 .category = "",
02537 .sql = sql
02538 };
02539 struct ast_config *cfg=NULL;
02540 struct odbc_obj *obj;
02541
02542 delete_file(dir, msgnum);
02543 obj = ast_odbc_request_obj(odbc_database, 0);
02544 if (obj) {
02545 ast_copy_string(fmt, vmfmts, sizeof(fmt));
02546 c = strchr(fmt, '|');
02547 if (c)
02548 *c = '\0';
02549 if (!strcasecmp(fmt, "wav49"))
02550 strcpy(fmt, "WAV");
02551 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
02552 if (msgnum > -1)
02553 make_file(fn, sizeof(fn), dir, msgnum);
02554 else
02555 ast_copy_string(fn, dir, sizeof(fn));
02556 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
02557 cfg = ast_config_load(full_fn);
02558 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
02559 fd = open(full_fn, O_RDWR);
02560 if (fd < 0) {
02561 ast_log(LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
02562 ast_odbc_release_obj(obj);
02563 goto yuck;
02564 }
02565 if (cfg) {
02566 d.context = ast_variable_retrieve(cfg, "message", "context");
02567 if (!d.context) d.context = "";
02568 d.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext");
02569 if (!d.macrocontext) d.macrocontext = "";
02570 d.callerid = ast_variable_retrieve(cfg, "message", "callerid");
02571 if (!d.callerid) d.callerid = "";
02572 d.origtime = ast_variable_retrieve(cfg, "message", "origtime");
02573 if (!d.origtime) d.origtime = "";
02574 d.duration = ast_variable_retrieve(cfg, "message", "duration");
02575 if (!d.duration) d.duration = "";
02576 d.category = ast_variable_retrieve(cfg, "message", "category");
02577 if (!d.category) d.category = "";
02578 }
02579 fdlen = lseek(fd, 0, SEEK_END);
02580 lseek(fd, 0, SEEK_SET);
02581 printf("Length is %zd\n", fdlen);
02582 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
02583 if (fdm == MAP_FAILED) {
02584 ast_log(LOG_WARNING, "Memory map failed!\n");
02585 ast_odbc_release_obj(obj);
02586 goto yuck;
02587 }
02588 d.recording = fdm;
02589 d.recordinglen = d.indlen = fdlen;
02590 if (!ast_strlen_zero(d.category))
02591 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,category) VALUES (?,?,?,?,?,?,?,?,?,?,?)",odbc_table);
02592 else
02593 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext) VALUES (?,?, ? , ?,?,?,?,?,?,?)",odbc_table);
02594 stmt = ast_odbc_prepare_and_execute(obj, insert_cb, &d);
02595 if (stmt) {
02596 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02597 }
02598 ast_odbc_release_obj(obj);
02599 } else
02600 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02601 yuck:
02602 if (cfg)
02603 ast_config_destroy(cfg);
02604 if (fdm != MAP_FAILED)
02605 munmap(fdm, fdlen);
02606 if (fd > -1)
02607 close(fd);
02608 return x;
02609 }
02610
02611 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
02612 {
02613 SQLHSTMT stmt;
02614 char sql[PATH_MAX];
02615 char msgnums[20];
02616 char msgnumd[20];
02617 struct odbc_obj *obj;
02618 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
02619 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
02620
02621 delete_file(ddir, dmsg);
02622 obj = ast_odbc_request_obj(odbc_database, 0);
02623 if (obj) {
02624 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
02625 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
02626 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?",odbc_table);
02627 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02628 if (!stmt)
02629 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02630 else
02631 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02632 ast_odbc_release_obj(obj);
02633 } else
02634 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
02635 return;
02636 }
02637
02638 #else
02639 #ifndef IMAP_STORAGE
02640 static int count_messages(struct ast_vm_user *vmu, char *dir)
02641 {
02642
02643
02644 int vmcount = 0;
02645 DIR *vmdir = NULL;
02646 struct dirent *vment = NULL;
02647
02648 if (vm_lock_path(dir))
02649 return ERROR_LOCK_PATH;
02650
02651 if ((vmdir = opendir(dir))) {
02652 while ((vment = readdir(vmdir))) {
02653 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4))
02654 vmcount++;
02655 }
02656 closedir(vmdir);
02657 }
02658 ast_unlock_path(dir);
02659
02660 return vmcount;
02661 }
02662
02663 static void rename_file(char *sfn, char *dfn)
02664 {
02665 char stxt[PATH_MAX];
02666 char dtxt[PATH_MAX];
02667 ast_filerename(sfn,dfn,NULL);
02668 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
02669 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
02670 rename(stxt, dtxt);
02671 }
02672 #endif
02673
02674
02675
02676
02677 #if (!defined(IMAP_STORAGE) && !defined(ODBC_STORAGE))
02678 static int last_message_index(struct ast_vm_user *vmu, char *dir)
02679 {
02680 int x;
02681 char fn[PATH_MAX];
02682
02683 if (vm_lock_path(dir))
02684 return ERROR_LOCK_PATH;
02685
02686 for (x = 0; x < vmu->maxmsg; x++) {
02687 make_file(fn, sizeof(fn), dir, x);
02688 if (ast_fileexists(fn, NULL, NULL) < 1)
02689 break;
02690 }
02691 ast_unlock_path(dir);
02692
02693 return x - 1;
02694 }
02695 #endif
02696 #endif
02697 #if (defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
02698 static int remove_file(char *dir, int msgnum)
02699 {
02700 char fn[PATH_MAX];
02701 char full_fn[PATH_MAX];
02702 char msgnums[80];
02703
02704 if (msgnum > -1) {
02705 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
02706 make_file(fn, sizeof(fn), dir, msgnum);
02707 } else {
02708 #ifndef IMAP_STORAGE
02709 ast_copy_string(fn, dir, sizeof(fn));
02710 #else
02711
02712
02713
02714 return 0;
02715 #endif
02716 }
02717 ast_filedelete(fn, NULL);
02718 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
02719 unlink(full_fn);
02720 return 0;
02721 }
02722 #endif
02723
02724 static int copy(char *infile, char *outfile)
02725 {
02726 int ifd;
02727 int ofd;
02728 int res;
02729 int len;
02730 char buf[4096];
02731
02732 #ifdef HARDLINK_WHEN_POSSIBLE
02733
02734 if (link(infile, outfile)) {
02735 #endif
02736 if ((ifd = open(infile, O_RDONLY)) < 0) {
02737 ast_log(LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
02738 return -1;
02739 }
02740 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
02741 ast_log(LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
02742 close(ifd);
02743 return -1;
02744 }
02745 do {
02746 len = read(ifd, buf, sizeof(buf));
02747 if (len < 0) {
02748 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
02749 close(ifd);
02750 close(ofd);
02751 unlink(outfile);
02752 }
02753 if (len) {
02754 res = write(ofd, buf, len);
02755 if (errno == ENOMEM || errno == ENOSPC || res != len) {
02756 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
02757 close(ifd);
02758 close(ofd);
02759 unlink(outfile);
02760 }
02761 }
02762 } while (len);
02763 close(ifd);
02764 close(ofd);
02765 return 0;
02766 #ifdef HARDLINK_WHEN_POSSIBLE
02767 } else {
02768
02769 return 0;
02770 }
02771 #endif
02772 }
02773
02774 static void copy_plain_file(char *frompath, char *topath)
02775 {
02776 char frompath2[PATH_MAX], topath2[PATH_MAX];
02777 ast_filecopy(frompath, topath, NULL);
02778 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
02779 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
02780 copy(frompath2, topath2);
02781 }
02782
02783 static int vm_delete(char *file)
02784 {
02785 char *txt;
02786 int txtsize = 0;
02787
02788 txtsize = (strlen(file) + 5)*sizeof(char);
02789 txt = alloca(txtsize);
02790
02791
02792
02793 snprintf(txt, txtsize, "%s.txt", file);
02794 unlink(txt);
02795 return ast_filedelete(file, NULL);
02796 }
02797
02798 static int inbuf(struct baseio *bio, FILE *fi)
02799 {
02800 int l;
02801
02802 if (bio->ateof)
02803 return 0;
02804
02805 if ((l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
02806 if (ferror(fi))
02807 return -1;
02808
02809 bio->ateof = 1;
02810 return 0;
02811 }
02812
02813 bio->iolen= l;
02814 bio->iocp= 0;
02815
02816 return 1;
02817 }
02818
02819 static int inchar(struct baseio *bio, FILE *fi)
02820 {
02821 if (bio->iocp>=bio->iolen) {
02822 if (!inbuf(bio, fi))
02823 return EOF;
02824 }
02825
02826 return bio->iobuf[bio->iocp++];
02827 }
02828
02829 static int ochar(struct baseio *bio, int c, FILE *so)
02830 {
02831 if (bio->linelength>=BASELINELEN) {
02832 if (fputs(eol,so)==EOF)
02833 return -1;
02834
02835 bio->linelength= 0;
02836 }
02837
02838 if (putc(((unsigned char)c),so)==EOF)
02839 return -1;
02840
02841 bio->linelength++;
02842
02843 return 1;
02844 }
02845
02846 static int base_encode(char *filename, FILE *so)
02847 {
02848 unsigned char dtable[BASEMAXINLINE];
02849 int i,hiteof= 0;
02850 FILE *fi;
02851 struct baseio bio;
02852
02853 memset(&bio, 0, sizeof(bio));
02854 bio.iocp = BASEMAXINLINE;
02855
02856 if (!(fi = fopen(filename, "rb"))) {
02857 ast_log(LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
02858 return -1;
02859 }
02860
02861 for (i= 0;i<9;i++) {
02862 dtable[i]= 'A'+i;
02863 dtable[i+9]= 'J'+i;
02864 dtable[26+i]= 'a'+i;
02865 dtable[26+i+9]= 'j'+i;
02866 }
02867 for (i= 0;i<8;i++) {
02868 dtable[i+18]= 'S'+i;
02869 dtable[26+i+18]= 's'+i;
02870 }
02871 for (i= 0;i<10;i++) {
02872 dtable[52+i]= '0'+i;
02873 }
02874 dtable[62]= '+';
02875 dtable[63]= '/';
02876
02877 while (!hiteof){
02878 unsigned char igroup[3],ogroup[4];
02879 int c,n;
02880
02881 igroup[0]= igroup[1]= igroup[2]= 0;
02882
02883 for (n= 0;n<3;n++) {
02884 if ((c = inchar(&bio, fi)) == EOF) {
02885 hiteof= 1;
02886 break;
02887 }
02888
02889 igroup[n]= (unsigned char)c;
02890 }
02891
02892 if (n> 0) {
02893 ogroup[0]= dtable[igroup[0]>>2];
02894 ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
02895 ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
02896 ogroup[3]= dtable[igroup[2]&0x3F];
02897
02898 if (n<3) {
02899 ogroup[3]= '=';
02900
02901 if (n<2)
02902 ogroup[2]= '=';
02903 }
02904
02905 for (i= 0;i<4;i++)
02906 ochar(&bio, ogroup[i], so);
02907 }
02908 }
02909
02910 fclose(fi);
02911
02912 if (fputs(eol,so)==EOF)
02913 return 0;
02914
02915 return 1;
02916 }
02917
02918 static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *dur, char *date, char *passdata, size_t passdatasize, const char *category)
02919 {
02920 char callerid[256];
02921
02922 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
02923 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
02924 snprintf(passdata, passdatasize, "%d", msgnum);
02925 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", passdata);
02926 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
02927 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
02928 pbx_builtin_setvar_helper(ast, "VM_CALLERID", ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, "Unknown Caller"));
02929 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (cidname ? cidname : "an unknown caller"));
02930 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (cidnum ? cidnum : "an unknown caller"));
02931 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
02932 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
02933 }
02934
02935 static char *quote(const char *from, char *to, size_t len)
02936 {
02937 char *ptr = to;
02938 *ptr++ = '"';
02939 for (; ptr < to + len - 1; from++) {
02940 if (*from == '"')
02941 *ptr++ = '\\';
02942 else if (*from == '\0')
02943 break;
02944 *ptr++ = *from;
02945 }
02946 if (ptr < to + len - 1)
02947 *ptr++ = '"';
02948 *ptr = '\0';
02949 return to;
02950 }
02951
02952
02953
02954
02955 static const struct tm *vmu_tm(const struct ast_vm_user *vmu, struct tm *tm)
02956 {
02957 const struct vm_zone *z = NULL;
02958 time_t t = time(NULL);
02959
02960
02961 if (!ast_strlen_zero(vmu->zonetag)) {
02962
02963 AST_LIST_LOCK(&zones);
02964 AST_LIST_TRAVERSE(&zones, z, list) {
02965 if (!strcmp(z->name, vmu->zonetag))
02966 break;
02967 }
02968 AST_LIST_UNLOCK(&zones);
02969 }
02970 ast_localtime(&t, tm, z ? z->timezone : NULL);
02971 return tm;
02972 }
02973
02974 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap)
02975 {
02976 char date[256];
02977 char host[MAXHOSTNAMELEN] = "";
02978 char who[256];
02979 char bound[256];
02980 char fname[256];
02981 char dur[256];
02982 char tmpcmd[256];
02983 char enc_cidnum[256] = "", enc_cidname[256] = "";
02984 struct tm tm;
02985 char *passdata2;
02986 size_t len_passdata;
02987 #ifdef IMAP_STORAGE
02988 #define ENDL "\r\n"
02989 #else
02990 #define ENDL "\n"
02991 #endif
02992
02993 if (cidnum) {
02994 strip_control(cidnum, enc_cidnum, sizeof(enc_cidnum));
02995 }
02996 if (cidname) {
02997 strip_control(cidname, enc_cidname, sizeof(enc_cidname));
02998 }
02999 gethostname(host, sizeof(host) - 1);
03000 if (strchr(srcemail, '@'))
03001 ast_copy_string(who, srcemail, sizeof(who));
03002 else {
03003 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
03004 }
03005 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
03006 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
03007 fprintf(p, "Date: %s" ENDL, date);
03008
03009
03010 strftime(date, sizeof(date), emaildateformat, &tm);
03011
03012 if (*fromstring) {
03013 struct ast_channel *ast;
03014 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) {
03015 char *passdata;
03016 int vmlen = strlen(fromstring)*3 + 200;
03017 if ((passdata = alloca(vmlen))) {
03018 memset(passdata, 0, vmlen);
03019 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, enc_cidnum, enc_cidname, dur, date, passdata, vmlen, category);
03020 pbx_substitute_variables_helper(ast, fromstring, passdata, vmlen);
03021 len_passdata = strlen(passdata) * 2 + 3;
03022 passdata2 = alloca(len_passdata);
03023 fprintf(p, "From: %s <%s>" ENDL, quote(passdata, passdata2, len_passdata), who);
03024 } else
03025 ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03026 ast_channel_free(ast);
03027 } else
03028 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03029 } else
03030 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
03031 len_passdata = strlen(vmu->fullname) * 2 + 3;
03032 passdata2 = alloca(len_passdata);
03033 fprintf(p, "To: %s <%s>" ENDL, quote(vmu->fullname, passdata2, len_passdata), vmu->email);
03034 if (emailsubject) {
03035 struct ast_channel *ast;
03036 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) {
03037 char *passdata;
03038 int vmlen = strlen(emailsubject)*3 + 200;
03039 if ((passdata = alloca(vmlen))) {
03040 memset(passdata, 0, vmlen);
03041 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
03042 pbx_substitute_variables_helper(ast, emailsubject, passdata, vmlen);
03043 fprintf(p, "Subject: %s" ENDL, passdata);
03044 } else {
03045 ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03046 }
03047 ast_channel_free(ast);
03048 } else {
03049 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03050 }
03051 } else if (*emailtitle) {
03052 fprintf(p, emailtitle, msgnum + 1, mailbox) ;
03053 fprintf(p, ENDL) ;
03054 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
03055 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
03056 } else {
03057 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
03058 }
03059 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1, (unsigned int)ast_random(), mailbox, (int)getpid(), host);
03060 if (imap) {
03061
03062 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
03063
03064 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
03065 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
03066 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
03067 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
03068 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
03069 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
03070 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
03071 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
03072 if (!ast_strlen_zero(category)) {
03073 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
03074 }
03075 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
03076 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long)time(NULL));
03077 }
03078 if (!ast_strlen_zero(cidnum)) {
03079 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
03080 }
03081 if (!ast_strlen_zero(cidname)) {
03082 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
03083 }
03084 fprintf(p, "MIME-Version: 1.0" ENDL);
03085 if (attach_user_voicemail) {
03086
03087 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox, (int)getpid(), (unsigned int)ast_random());
03088
03089 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
03090 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
03091 fprintf(p, "--%s" ENDL, bound);
03092 }
03093 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
03094 if (emailbody) {
03095 struct ast_channel *ast;
03096 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) {
03097 char *passdata;
03098 int vmlen = strlen(emailbody)*3 + 200;
03099 if ((passdata = alloca(vmlen))) {
03100 memset(passdata, 0, vmlen);
03101 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
03102 pbx_substitute_variables_helper(ast, emailbody, passdata, vmlen);
03103 fprintf(p, "%s" ENDL, passdata);
03104 } else
03105 ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03106 ast_channel_free(ast);
03107 } else
03108 ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03109 } else {
03110 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a %s long message (number %d)" ENDL
03111
03112 "in mailbox %s from %s, on %s so you might" ENDL
03113 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname,
03114 dur, msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
03115 }
03116 if (attach_user_voicemail) {
03117
03118 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
03119 char tmpdir[256], newtmp[256];
03120 int tmpfd = -1;
03121
03122 if (vmu->volgain < -.001 || vmu->volgain > .001) {
03123 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
03124 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
03125 tmpfd = mkstemp(newtmp);
03126 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
03127 if (option_debug > 2)
03128 ast_log(LOG_DEBUG, "newtmp: %s\n", newtmp);
03129 if (tmpfd > -1) {
03130 int soxstatus;
03131 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
03132 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
03133 attach = newtmp;
03134 if (option_debug > 2) {
03135 ast_log(LOG_DEBUG, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
03136 }
03137 } else {
03138 ast_log(LOG_WARNING, "Sox failed to reencode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
03139 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
03140 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
03141 }
03142 }
03143 }
03144 fprintf(p, "--%s" ENDL, bound);
03145 fprintf(p, "Content-Type: %s%s; name=\"msg%04d.%s\"" ENDL, ctype, format, msgnum + 1, format);
03146 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
03147 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
03148 fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"" ENDL ENDL, msgnum + 1, format);
03149 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
03150 base_encode(fname, p);
03151 fprintf(p, ENDL "--%s--" ENDL "." ENDL, bound);
03152 if (tmpfd > -1) {
03153 unlink(fname);
03154 close(tmpfd);
03155 unlink(newtmp);
03156 }
03157 }
03158 #undef ENDL
03159 }
03160 static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category)
03161 {
03162 FILE *p=NULL;
03163 char tmp[80] = "/tmp/astmail-XXXXXX";
03164 char tmp2[256];
03165
03166 if (vmu && ast_strlen_zero(vmu->email)) {
03167 ast_log(LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
03168 return(0);
03169 }
03170 if (!strcmp(format, "wav49"))
03171 format = "WAV";
03172 if (option_debug > 2)
03173 ast_log(LOG_DEBUG, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
03174
03175
03176 if ((p = vm_mkftemp(tmp)) == NULL) {
03177 ast_log(LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
03178 return -1;
03179 } else {
03180 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, cidnum, cidname, attach, format, duration, attach_user_voicemail, chan, category, 0);
03181 fclose(p);
03182 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
03183 ast_safe_system(tmp2);
03184 if (option_debug > 2)
03185 ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
03186 }
03187 return 0;
03188 }
03189
03190 static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu, const char *category)
03191 {
03192 char date[256];
03193 char host[MAXHOSTNAMELEN] = "";
03194 char who[256];
03195 char dur[PATH_MAX];
03196 char tmp[80] = "/tmp/astmail-XXXXXX";
03197 char tmp2[PATH_MAX];
03198 struct tm tm;
03199 FILE *p;
03200
03201 if ((p = vm_mkftemp(tmp)) == NULL) {
03202 ast_log(LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
03203 return -1;
03204 } else {
03205 gethostname(host, sizeof(host)-1);
03206 if (strchr(srcemail, '@'))
03207 ast_copy_string(who, srcemail, sizeof(who));
03208 else {
03209 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
03210 }
03211 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
03212 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
03213 fprintf(p, "Date: %s\n", date);
03214
03215 if (*pagerfromstring) {
03216 struct ast_channel *ast;
03217 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) {
03218 char *passdata;
03219 int vmlen = strlen(fromstring)*3 + 200;
03220 if ((passdata = alloca(vmlen))) {
03221 memset(passdata, 0, vmlen);
03222 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
03223 pbx_substitute_variables_helper(ast, pagerfromstring, passdata, vmlen);
03224 fprintf(p, "From: %s <%s>\n", passdata, who);
03225 } else
03226 ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03227 ast_channel_free(ast);
03228 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03229 } else
03230 fprintf(p, "From: Asterisk PBX <%s>\n", who);
03231 fprintf(p, "To: %s\n", pager);
03232 if (pagersubject) {
03233 struct ast_channel *ast;
03234 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) {
03235 char *passdata;
03236 int vmlen = strlen(pagersubject) * 3 + 200;
03237 if ((passdata = alloca(vmlen))) {
03238 memset(passdata, 0, vmlen);
03239 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
03240 pbx_substitute_variables_helper(ast, pagersubject, passdata, vmlen);
03241 fprintf(p, "Subject: %s\n\n", passdata);
03242 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03243 ast_channel_free(ast);
03244 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03245 } else
03246 fprintf(p, "Subject: New VM\n\n");
03247 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
03248 if (pagerbody) {
03249 struct ast_channel *ast;
03250 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) {
03251 char *passdata;
03252 int vmlen = strlen(pagerbody)*3 + 200;
03253 if ((passdata = alloca(vmlen))) {
03254 memset(passdata, 0, vmlen);
03255 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category);
03256 pbx_substitute_variables_helper(ast, pagerbody, passdata, vmlen);
03257 fprintf(p, "%s\n", passdata);
03258 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
03259 ast_channel_free(ast);
03260 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
03261 } else {
03262 fprintf(p, "New %s long msg in box %s\n"
03263 "from %s, on %s", dur, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
03264 }
03265 fclose(p);
03266 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
03267 ast_safe_system(tmp2);
03268 if (option_debug > 2)
03269 ast_log(LOG_DEBUG, "Sent page to %s with command '%s'\n", pager, mailcmd);
03270 }
03271 return 0;
03272 }
03273
03274 static int get_date(char *s, int len)
03275 {
03276 struct tm tm;
03277 time_t t;
03278
03279 time(&t);
03280
03281 ast_localtime(&t, &tm, NULL);
03282
03283 return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
03284 }
03285
03286 static int play_greeting(struct ast_channel *chan, struct ast_vm_user *vmu, char *filename, char *ecodes)
03287 {
03288 int res = -2;
03289
03290 #ifdef ODBC_STORAGE
03291 int success =
03292 #endif
03293 RETRIEVE(filename, -1, vmu);
03294 if (ast_fileexists(filename, NULL, NULL) > 0) {
03295 res = ast_streamfile(chan, filename, chan->language);
03296 if (res > -1)
03297 res = ast_waitstream(chan, ecodes);
03298 #ifdef ODBC_STORAGE
03299 if (success == -1) {
03300
03301 if (option_debug)
03302 ast_log(LOG_DEBUG, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
03303 store_file(filename, vmu->mailbox, vmu->context, -1);
03304 }
03305 #endif
03306 }
03307 DISPOSE(filename, -1);
03308
03309 return res;
03310 }
03311
03312 static int invent_message(struct ast_channel *chan, struct ast_vm_user *vmu, char *ext, int busy, char *ecodes)
03313 {
03314 int res;
03315 char fn[PATH_MAX];
03316 char dest[PATH_MAX];
03317
03318 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, ext);
03319
03320 if ((res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "greet"))) {
03321 ast_log(LOG_WARNING, "Failed to make directory(%s)\n", fn);
03322 return -1;
03323 }
03324
03325 res = play_greeting(chan, vmu, fn, ecodes);
03326 if (res == -2) {
03327
03328 res = ast_stream_and_wait(chan, "vm-theperson", chan->language, ecodes);
03329 if (res)
03330 return res;
03331 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
03332 }
03333
03334 if (res)
03335 return res;
03336
03337 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", chan->language, ecodes);
03338 return res;
03339 }
03340
03341 static void free_zone(struct vm_zone *z)
03342 {
03343 free(z);
03344 }
03345
03346 #ifdef ODBC_STORAGE
03347
03348 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
03349 {
03350 int x = -1;
03351 int res;
03352 SQLHSTMT stmt;
03353 char sql[PATH_MAX];
03354 char rowdata[20];
03355 char tmp[PATH_MAX] = "";
03356 struct odbc_obj *obj;
03357 char *context;
03358 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
03359
03360 if (newmsgs)
03361 *newmsgs = 0;
03362 if (oldmsgs)
03363 *oldmsgs = 0;
03364
03365
03366 if (ast_strlen_zero(mailbox))
03367 return 0;
03368
03369 ast_copy_string(tmp, mailbox, sizeof(tmp));
03370
03371 context = strchr(tmp, '@');
03372 if (context) {
03373 *context = '\0';
03374 context++;
03375 } else
03376 context = "default";
03377
03378 obj = ast_odbc_request_obj(odbc_database, 0);
03379 if (obj) {
03380 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
03381 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03382 if (!stmt) {
03383 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03384 ast_odbc_release_obj(obj);
03385 goto yuck;
03386 }
03387 res = SQLFetch(stmt);
03388 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03389 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03390 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03391 ast_odbc_release_obj(obj);
03392 goto yuck;
03393 }
03394 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03395 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03396 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03397 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03398 ast_odbc_release_obj(obj);
03399 goto yuck;
03400 }
03401 *newmsgs = atoi(rowdata);
03402 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03403
03404 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
03405 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03406 if (!stmt) {
03407 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03408 ast_odbc_release_obj(obj);
03409 goto yuck;
03410 }
03411 res = SQLFetch(stmt);
03412 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03413 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03414 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03415 ast_odbc_release_obj(obj);
03416 goto yuck;
03417 }
03418 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03419 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03420 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03421 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03422 ast_odbc_release_obj(obj);
03423 goto yuck;
03424 }
03425 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03426 ast_odbc_release_obj(obj);
03427 *oldmsgs = atoi(rowdata);
03428 x = 0;
03429 } else
03430 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03431
03432 yuck:
03433 return x;
03434 }
03435
03436 static int messagecount(const char *context, const char *mailbox, const char *folder)
03437 {
03438 struct odbc_obj *obj = NULL;
03439 int nummsgs = 0;
03440 int res;
03441 SQLHSTMT stmt = NULL;
03442 char sql[PATH_MAX];
03443 char rowdata[20];
03444 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
03445 if (!folder)
03446 folder = "INBOX";
03447
03448 if (ast_strlen_zero(mailbox))
03449 return 0;
03450
03451 obj = ast_odbc_request_obj(odbc_database, 0);
03452 if (obj) {
03453 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
03454 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03455 if (!stmt) {
03456 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03457 goto yuck;
03458 }
03459 res = SQLFetch(stmt);
03460 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03461 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03462 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03463 goto yuck;
03464 }
03465 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03466 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03467 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03468 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03469 goto yuck;
03470 }
03471 nummsgs = atoi(rowdata);
03472 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03473 } else
03474 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03475
03476 yuck:
03477 if (obj)
03478 ast_odbc_release_obj(obj);
03479 return nummsgs;
03480 }
03481
03482 static int has_voicemail(const char *mailbox, const char *folder)
03483 {
03484 char tmp[256], *tmp2 = tmp, *mbox, *context;
03485 ast_copy_string(tmp, mailbox, sizeof(tmp));
03486 while ((context = mbox = strsep(&tmp2, ","))) {
03487 strsep(&context, "@");
03488 if (ast_strlen_zero(context))
03489 context = "default";
03490 if (messagecount(context, mbox, folder))
03491 return 1;
03492 }
03493 return 0;
03494 }
03495 #endif
03496 #ifndef IMAP_STORAGE
03497
03498 static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt, char *dir)
03499 {
03500 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
03501 const char *frombox = mbox(imbox);
03502 int recipmsgnum;
03503
03504 ast_log(LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
03505
03506 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
03507
03508 if (!dir)
03509 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
03510 else
03511 ast_copy_string(fromdir, dir, sizeof(fromdir));
03512
03513 make_file(frompath, sizeof(frompath), fromdir, msgnum);
03514
03515 if (vm_lock_path(todir))
03516 return ERROR_LOCK_PATH;
03517
03518 recipmsgnum = 0;
03519 do {
03520 make_file(topath, sizeof(topath), todir, recipmsgnum);
03521 if (!EXISTS(todir, recipmsgnum, topath, chan->language))
03522 break;
03523 recipmsgnum++;
03524 } while (recipmsgnum < recip->maxmsg);
03525 if (recipmsgnum < recip->maxmsg) {
03526 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
03527 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
03528 } else {
03529
03530
03531
03532
03533
03534 copy_plain_file(frompath, topath);
03535 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL);
03536 vm_delete(topath);
03537 }
03538 } else {
03539 ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
03540 }
03541 ast_unlock_path(todir);
03542 notify_new_message(chan, recip, recipmsgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL));
03543
03544 return 0;
03545 }
03546 #endif
03547 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
03548 static int messagecount(const char *context, const char *mailbox, const char *folder)
03549 {
03550 return __has_voicemail(context, mailbox, folder, 0);
03551 }
03552
03553
03554 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
03555 {
03556 DIR *dir;
03557 struct dirent *de;
03558 char fn[256];
03559 int ret = 0;
03560 if (!folder)
03561 folder = "INBOX";
03562
03563 if (ast_strlen_zero(mailbox))
03564 return 0;
03565 if (!context)
03566 context = "default";
03567 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
03568 dir = opendir(fn);
03569 if (!dir)
03570 return 0;
03571 while ((de = readdir(dir))) {
03572 if (!strncasecmp(de->d_name, "msg", 3)) {
03573 if (shortcircuit) {
03574 ret = 1;
03575 break;
03576 } else if (!strncasecmp(de->d_name + 8, "txt", 3))
03577 ret++;
03578 }
03579 }
03580 closedir(dir);
03581 return ret;
03582 }
03583
03584
03585 static int has_voicemail(const char *mailbox, const char *folder)
03586 {
03587 char tmp[256], *tmp2 = tmp, *mbox, *context;
03588 ast_copy_string(tmp, mailbox, sizeof(tmp));
03589 while ((mbox = strsep(&tmp2, ","))) {
03590 if ((context = strchr(mbox, '@')))
03591 *context++ = '\0';
03592 else
03593 context = "default";
03594 if (__has_voicemail(context, mbox, folder, 1))
03595 return 1;
03596 }
03597 return 0;
03598 }
03599
03600
03601 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
03602 {
03603 char tmp[256];
03604 char *context;
03605
03606 if (newmsgs)
03607 *newmsgs = 0;
03608 if (oldmsgs)
03609 *oldmsgs = 0;
03610
03611 if (ast_strlen_zero(mailbox))
03612 return 0;
03613 if (strchr(mailbox, ',')) {
03614 int tmpnew, tmpold;
03615 char *mb, *cur;
03616
03617 ast_copy_string(tmp, mailbox, sizeof(tmp));
03618 mb = tmp;
03619 while ((cur = strsep(&mb, ", "))) {
03620 if (!ast_strlen_zero(cur)) {
03621 if (inboxcount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
03622 return -1;
03623 else {
03624 if (newmsgs)
03625 *newmsgs += tmpnew;
03626 if (oldmsgs)
03627 *oldmsgs += tmpold;
03628 }
03629 }
03630 }
03631 return 0;
03632 }
03633 ast_copy_string(tmp, mailbox, sizeof(tmp));
03634 context = strchr(tmp, '@');
03635 if (context) {
03636 *context = '\0';
03637 context++;
03638 } else
03639 context = "default";
03640 if (newmsgs)
03641 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
03642 if (oldmsgs)
03643 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
03644 return 0;
03645 }
03646
03647 #endif
03648
03649 static void run_externnotify(char *context, char *extension)
03650 {
03651 char arguments[255];
03652 char ext_context[256] = "";
03653 int newvoicemails = 0, oldvoicemails = 0;
03654 struct ast_smdi_mwi_message *mwi_msg;
03655
03656 if (!ast_strlen_zero(context))
03657 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
03658 else
03659 ast_copy_string(ext_context, extension, sizeof(ext_context));
03660
03661 if (!strcasecmp(externnotify, "smdi")) {
03662 if (ast_app_has_voicemail(ext_context, NULL))
03663 ast_smdi_mwi_set(smdi_iface, extension);
03664 else
03665 ast_smdi_mwi_unset(smdi_iface, extension);
03666
03667 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
03668 ast_log(LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
03669 if (!strncmp(mwi_msg->cause, "INV", 3))
03670 ast_log(LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
03671 else if (!strncmp(mwi_msg->cause, "BLK", 3))
03672 ast_log(LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
03673 ast_log(LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
03674 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
03675 } else {
03676 if (option_debug)
03677 ast_log(LOG_DEBUG, "Successfully executed SMDI MWI change for %s\n", extension);
03678 }
03679 } else if (!ast_strlen_zero(externnotify)) {
03680 if (inboxcount(ext_context, &newvoicemails, &oldvoicemails)) {
03681 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
03682 } else {
03683 snprintf(arguments, sizeof(arguments), "%s %s %s %d&", externnotify, context, extension, newvoicemails);
03684 if (option_debug)
03685 ast_log(LOG_DEBUG, "Executing %s\n", arguments);
03686 ast_safe_system(arguments);
03687 }
03688 }
03689 }
03690
03691 struct leave_vm_options {
03692 unsigned int flags;
03693 signed char record_gain;
03694 };
03695
03696 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
03697 {
03698 #ifdef IMAP_STORAGE
03699 int newmsgs, oldmsgs;
03700 #endif
03701 struct vm_state *vms = NULL;
03702 char txtfile[PATH_MAX], tmptxtfile[PATH_MAX];
03703 char callerid[256];
03704 FILE *txt;
03705 char date[256];
03706 int txtdes;
03707 int res = 0;
03708 int msgnum;
03709 int duration = 0;
03710 int ausemacro = 0;
03711 int ousemacro = 0;
03712 int ouseexten = 0;
03713 char dir[PATH_MAX], tmpdir[PATH_MAX];
03714 char dest[PATH_MAX];
03715 char fn[PATH_MAX];
03716 char prefile[PATH_MAX] = "";
03717 char tempfile[PATH_MAX] = "";
03718 char ext_context[256] = "";
03719 char fmt[80];
03720 char *context;
03721 char ecodes[16] = "#";
03722 char tmp[1024] = "", *tmpptr;
03723 struct ast_vm_user *vmu;
03724 struct ast_vm_user svm;
03725 const char *category = NULL;
03726
03727 ast_copy_string(tmp, ext, sizeof(tmp));
03728 ext = tmp;
03729 context = strchr(tmp, '@');
03730 if (context) {
03731 *context++ = '\0';
03732 tmpptr = strchr(context, '&');
03733 } else {
03734 tmpptr = strchr(ext, '&');
03735 }
03736
03737 if (tmpptr)
03738 *tmpptr++ = '\0';
03739
03740 category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
03741
03742 if (option_debug > 2)
03743 ast_log(LOG_DEBUG, "Before find_user\n");
03744 if (!(vmu = find_user(&svm, context, ext))) {
03745 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
03746 if (ast_test_flag(options, OPT_PRIORITY_JUMP) || ast_opt_priority_jumping)
03747 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
03748 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
03749 return res;
03750 }
03751
03752 if (strcmp(vmu->context, "default"))
03753 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
03754 else
03755 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
03756 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
03757 res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "busy");
03758 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
03759 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
03760 res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "unavail");
03761 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
03762 }
03763 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
03764 if ((res = create_dirpath(dest, sizeof(dest), vmu->context, ext, "temp"))) {
03765 ast_log(LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
03766 return -1;
03767 }
03768 RETRIEVE(tempfile, -1, vmu);
03769 if (ast_fileexists(tempfile, NULL, NULL) > 0)
03770 ast_copy_string(prefile, tempfile, sizeof(prefile));
03771 DISPOSE(tempfile, -1);
03772
03773 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
03774 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp");
03775
03776
03777 if (ast_test_flag(vmu, VM_OPERATOR)) {
03778 if (!ast_strlen_zero(vmu->exit)) {
03779 if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num)) {
03780 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
03781 ouseexten = 1;
03782 }
03783 } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num)) {
03784 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
03785 ouseexten = 1;
03786 }
03787 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) {
03788 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
03789 ousemacro = 1;
03790 }
03791 }
03792
03793 if (!ast_strlen_zero(vmu->exit)) {
03794 if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num))
03795 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
03796 } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num))
03797 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
03798 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) {
03799 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
03800 ausemacro = 1;
03801 }
03802
03803
03804 if (!ast_strlen_zero(prefile)) {
03805 res = play_greeting(chan, vmu, prefile, ecodes);
03806 if (res == -2) {
03807
03808 if (option_debug)
03809 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
03810 res = invent_message(chan, vmu, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
03811 }
03812 if (res < 0) {
03813 if (option_debug)
03814 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
03815 free_user(vmu);
03816 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
03817 return -1;
03818 }
03819 }
03820 if (res == '#') {
03821
03822 ast_set_flag(options, OPT_SILENT);
03823 res = 0;
03824 }
03825 if (!res && !ast_test_flag(options, OPT_SILENT)) {
03826 res = ast_stream_and_wait(chan, INTRO, chan->language, ecodes);
03827 if (res == '#') {
03828 ast_set_flag(options, OPT_SILENT);
03829 res = 0;
03830 }
03831 }
03832 if (res > 0)
03833 ast_stopstream(chan);
03834
03835
03836 if (res == '*') {
03837 chan->exten[0] = 'a';
03838 chan->exten[1] = '\0';
03839 if (!ast_strlen_zero(vmu->exit)) {
03840 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
03841 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
03842 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
03843 }
03844 chan->priority = 0;
03845 free_user(vmu);
03846 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
03847 return 0;
03848 }
03849
03850
03851 if (res == '0') {
03852 transfer:
03853 if (ouseexten || ousemacro) {
03854 chan->exten[0] = 'o';
03855 chan->exten[1] = '\0';
03856 if (!ast_strlen_zero(vmu->exit)) {
03857 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
03858 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
03859 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
03860 }
03861 ast_play_and_wait(chan, "transfer");
03862 chan->priority = 0;
03863 free_user(vmu);
03864 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
03865 }
03866 return 0;
03867 }
03868 if (res < 0) {
03869 free_user(vmu);
03870 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
03871 return -1;
03872 }
03873
03874 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03875 if (!ast_strlen_zero(fmt)) {
03876 msgnum = 0;
03877
03878 #ifdef IMAP_STORAGE
03879
03880
03881 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
03882 if (res < 0) {
03883 ast_log(LOG_NOTICE,"Can not leave voicemail, unable to count messages\n");
03884 return -1;
03885 }
03886 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
03887
03888
03889 if (!(vms = create_vm_state_from_user(vmu))) {
03890 ast_log(LOG_ERROR, "Couldn't allocate necessary space\n");
03891 return -1;
03892 }
03893 }
03894 vms->newmessages++;
03895
03896 msgnum = newmsgs + oldmsgs;
03897 if (option_debug > 2)
03898 ast_log(LOG_DEBUG, "Messagecount set to %d\n",msgnum);
03899 snprintf(fn, sizeof(fn), "%s/imap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
03900
03901 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
03902
03903
03904 check_quota(vms, imapfolder);
03905 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
03906 if (option_debug)
03907 ast_log(LOG_DEBUG, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
03908 ast_play_and_wait(chan, "vm-mailboxfull");
03909 return -1;
03910 }
03911 if (option_debug > 2)
03912 ast_log(LOG_DEBUG, "Checking message number quota - mailbox has %d messages, maximum is set to %d\n",msgnum,vmu->maxmsg);
03913 if (msgnum >= vmu->maxmsg) {
03914 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
03915 if (!res)
03916 res = ast_waitstream(chan, "");
03917 ast_log(LOG_WARNING, "No more messages possible\n");
03918 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
03919 goto leave_vm_out;
03920 }
03921
03922
03923 if (msgnum >= vmu->maxmsg) {
03924 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u > %u)\n", msgnum, vmu->maxmsg);
03925 ast_play_and_wait(chan, "vm-mailboxfull");
03926 return -1;
03927 }
03928 #else
03929 if (count_messages(vmu, dir) >= vmu->maxmsg) {
03930 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
03931 if (!res)
03932 res = ast_waitstream(chan, "");
03933 ast_log(LOG_WARNING, "No more messages possible\n");
03934 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
03935 goto leave_vm_out;
03936 }
03937
03938 #endif
03939 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
03940 txtdes = mkstemp(tmptxtfile);
03941 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
03942 if (txtdes < 0) {
03943 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
03944 if (!res)
03945 res = ast_waitstream(chan, "");
03946 ast_log(LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
03947 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
03948 goto leave_vm_out;
03949 }
03950
03951
03952 if (res >= 0) {
03953
03954 res = ast_stream_and_wait(chan, "beep", chan->language, "");
03955 }
03956
03957
03958 txt = fdopen(txtdes, "w+");
03959 if (txt) {
03960 get_date(date, sizeof(date));
03961 fprintf(txt,
03962 ";\n"
03963 "; Message Information file\n"
03964 ";\n"
03965 "[message]\n"
03966 "origmailbox=%s\n"
03967 "context=%s\n"
03968 "macrocontext=%s\n"
03969 "exten=%s\n"
03970 "priority=%d\n"
03971 "callerchan=%s\n"
03972 "callerid=%s\n"
03973 "origdate=%s\n"
03974 "origtime=%ld\n"
03975 "category=%s\n",
03976 ext,
03977 chan->context,
03978 chan->macrocontext,
03979 chan->exten,
03980 chan->priority,
03981 chan->name,
03982 ast_callerid_merge(callerid, sizeof(callerid), S_OR(chan->cid.cid_name, NULL), S_OR(chan->cid.cid_num, NULL), "Unknown"),
03983 date, (long)time(NULL),
03984 category ? category : "");
03985 } else
03986 ast_log(LOG_WARNING, "Error opening text file for output\n");
03987 res = play_record_review(chan, NULL, tmptxtfile, vmmaxmessage, fmt, 1, vmu, &duration, NULL, options->record_gain, vms);
03988
03989 if (txt) {
03990 if (duration < vmminmessage) {
03991 fclose(txt);
03992 if (option_verbose > 2)
03993 ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminmessage);
03994 ast_filedelete(tmptxtfile, NULL);
03995 unlink(tmptxtfile);
03996 } else {
03997 fprintf(txt, "duration=%d\n", duration);
03998 fclose(txt);
03999 if (vm_lock_path(dir)) {
04000 ast_log(LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
04001
04002 ast_filedelete(tmptxtfile, NULL);
04003 unlink(tmptxtfile);
04004 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
04005 if (option_debug)
04006 ast_log(LOG_DEBUG, "The recorded media file is gone, so we should remove the .txt file too!\n");
04007 unlink(tmptxtfile);
04008 ast_unlock_path(dir);
04009 } else {
04010 for (;;) {
04011 make_file(fn, sizeof(fn), dir, msgnum);
04012 if (!EXISTS(dir, msgnum, fn, NULL))
04013 break;
04014 msgnum++;
04015 }
04016
04017
04018 #ifndef IMAP_STORAGE
04019 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
04020 #else
04021 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
04022 #endif
04023
04024 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
04025 ast_filerename(tmptxtfile, fn, NULL);
04026 rename(tmptxtfile, txtfile);
04027
04028 ast_unlock_path(dir);
04029
04030
04031
04032 if (ast_fileexists(fn, NULL, NULL) > 0) {
04033 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms);
04034 }
04035
04036
04037 while (tmpptr) {
04038 struct ast_vm_user recipu, *recip;
04039 char *exten, *context;
04040
04041 exten = strsep(&tmpptr, "&");
04042 context = strchr(exten, '@');
04043 if (context) {
04044 *context = '\0';
04045 context++;
04046 }
04047 if ((recip = find_user(&recipu, context, exten))) {
04048 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir);
04049 free_user(recip);
04050 }
04051 }
04052
04053 if (ast_fileexists(fn, NULL, NULL)) {
04054 notify_new_message(chan, vmu, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL));
04055 DISPOSE(dir, msgnum);
04056 }
04057 }
04058 }
04059 }
04060 if (res == '0') {
04061 goto transfer;
04062 } else if (res > 0)
04063 res = 0;
04064
04065 if (duration < vmminmessage)
04066
04067 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
04068 else
04069 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
04070 } else
04071 ast_log(LOG_WARNING, "No format for saving voicemail?\n");
04072 leave_vm_out:
04073 free_user(vmu);
04074
04075 return res;
04076 }
04077
04078 #ifndef IMAP_STORAGE
04079 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir)
04080 {
04081
04082
04083 int x,dest;
04084 char sfn[PATH_MAX];
04085 char dfn[PATH_MAX];
04086
04087 if (vm_lock_path(dir))
04088 return ERROR_LOCK_PATH;
04089
04090 for (x = 0, dest = 0; x < vmu->maxmsg; x++) {
04091 make_file(sfn, sizeof(sfn), dir, x);
04092 if (EXISTS(dir, x, sfn, NULL)) {
04093
04094 if (x != dest) {
04095 make_file(dfn, sizeof(dfn), dir, dest);
04096 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
04097 }
04098
04099 dest++;
04100 }
04101 }
04102 ast_unlock_path(dir);
04103
04104 return 0;
04105 }
04106 #endif
04107
04108 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
04109 {
04110 int d;
04111 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, (char *) NULL);
04112 return d;
04113 }
04114
04115 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
04116 {
04117 #ifdef IMAP_STORAGE
04118
04119
04120 char sequence[10];
04121
04122 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
04123 if (option_debug > 2)
04124 ast_log(LOG_DEBUG, "Copying sequence %s to mailbox %s\n",sequence,(char *) mbox(box));
04125 if (box == 1) {
04126 mail_setflag(vms->mailstream, sequence, "\\Seen");
04127 } else if (box == 0) {
04128 mail_clearflag(vms->mailstream, sequence, "\\Seen");
04129 }
04130 if (!strcasecmp(mbox(0), vms->curbox) && (box == 0 || box == 1))
04131 return 0;
04132 else
04133 return !mail_copy(vms->mailstream,sequence,(char *) mbox(box));
04134 #else
04135 char *dir = vms->curdir;
04136 char *username = vms->username;
04137 char *context = vmu->context;
04138 char sfn[PATH_MAX];
04139 char dfn[PATH_MAX];
04140 char ddir[PATH_MAX];
04141 const char *dbox = mbox(box);
04142 int x;
04143 make_file(sfn, sizeof(sfn), dir, msg);
04144 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
04145
04146 if (vm_lock_path(ddir))
04147 return ERROR_LOCK_PATH;
04148
04149 for (x = 0; x < vmu->maxmsg; x++) {
04150 make_file(dfn, sizeof(dfn), ddir, x);
04151 if (!EXISTS(ddir, x, dfn, NULL))
04152 break;
04153 }
04154 if (x >= vmu->maxmsg) {
04155 ast_unlock_path(ddir);
04156 return ERROR_MAILBOX_FULL;
04157 }
04158 if (strcmp(sfn, dfn)) {
04159 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
04160 }
04161 ast_unlock_path(ddir);
04162 #endif
04163 return 0;
04164 }
04165
04166 static int adsi_logo(unsigned char *buf)
04167 {
04168 int bytes = 0;
04169 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
04170 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
04171 return bytes;
04172 }
04173
04174 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
04175 {
04176 unsigned char buf[256];
04177 int bytes=0;
04178 int x;
04179 char num[5];
04180
04181 *useadsi = 0;
04182 bytes += ast_adsi_data_mode(buf + bytes);
04183 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04184
04185 bytes = 0;
04186 bytes += adsi_logo(buf);
04187 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
04188 #ifdef DISPLAY
04189 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
04190 #endif
04191 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04192 bytes += ast_adsi_data_mode(buf + bytes);
04193 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04194
04195 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
04196 bytes = 0;
04197 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
04198 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
04199 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04200 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04201 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04202 return 0;
04203 }
04204
04205 #ifdef DISPLAY
04206
04207 bytes = 0;
04208 bytes += ast_adsi_logo(buf);
04209 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
04210 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
04211 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04212 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04213 #endif
04214 bytes = 0;
04215 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
04216 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
04217 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
04218 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
04219 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
04220 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
04221 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04222
04223 #ifdef DISPLAY
04224
04225 bytes = 0;
04226 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
04227 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04228
04229 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04230 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04231 #endif
04232
04233 bytes = 0;
04234
04235 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
04236 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
04237 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
04238 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
04239 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
04240 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
04241 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04242
04243 #ifdef DISPLAY
04244
04245 bytes = 0;
04246 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
04247 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04248 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04249 #endif
04250
04251 bytes = 0;
04252 for (x=0;x<5;x++) {
04253 snprintf(num, sizeof(num), "%d", x);
04254 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
04255 }
04256 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
04257 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04258
04259 #ifdef DISPLAY
04260
04261 bytes = 0;
04262 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
04263 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04264 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04265 #endif
04266
04267 if (ast_adsi_end_download(chan)) {
04268 bytes = 0;
04269 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
04270 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
04271 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04272 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04273 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04274 return 0;
04275 }
04276 bytes = 0;
04277 bytes += ast_adsi_download_disconnect(buf + bytes);
04278 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04279 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
04280
04281 if (option_debug)
04282 ast_log(LOG_DEBUG, "Done downloading scripts...\n");
04283
04284 #ifdef DISPLAY
04285
04286 bytes = 0;
04287 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
04288 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04289 #endif
04290 if (option_debug)
04291 ast_log(LOG_DEBUG, "Restarting session...\n");
04292
04293 bytes = 0;
04294
04295 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
04296 *useadsi = 1;
04297 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
04298 } else
04299 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
04300
04301 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04302 return 0;
04303 }
04304
04305 static void adsi_begin(struct ast_channel *chan, int *useadsi)
04306 {
04307 int x;
04308 if (!ast_adsi_available(chan))
04309 return;
04310 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
04311 if (x < 0)
04312 return;
04313 if (!x) {
04314 if (adsi_load_vmail(chan, useadsi)) {
04315 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
04316 return;
04317 }
04318 } else
04319 *useadsi = 1;
04320 }
04321
04322 static void adsi_login(struct ast_channel *chan)
04323 {
04324 unsigned char buf[256];
04325 int bytes=0;
04326 unsigned char keys[8];
04327 int x;
04328 if (!ast_adsi_available(chan))
04329 return;
04330
04331 for (x=0;x<8;x++)
04332 keys[x] = 0;
04333
04334 keys[3] = ADSI_KEY_APPS + 3;
04335
04336 bytes += adsi_logo(buf + bytes);
04337 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
04338 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
04339 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04340 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
04341 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
04342 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
04343 bytes += ast_adsi_set_keys(buf + bytes, keys);
04344 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04345 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04346 }
04347
04348 static void adsi_password(struct ast_channel *chan)
04349 {
04350 unsigned char buf[256];
04351 int bytes=0;
04352 unsigned char keys[8];
04353 int x;
04354 if (!ast_adsi_available(chan))
04355 return;
04356
04357 for (x=0;x<8;x++)
04358 keys[x] = 0;
04359
04360 keys[3] = ADSI_KEY_APPS + 3;
04361
04362 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04363 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
04364 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
04365 bytes += ast_adsi_set_keys(buf + bytes, keys);
04366 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04367 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04368 }
04369
04370 static void adsi_folders(struct ast_channel *chan, int start, char *label)
04371 {
04372 unsigned char buf[256];
04373 int bytes=0;
04374 unsigned char keys[8];
04375 int x,y;
04376
04377 if (!ast_adsi_available(chan))
04378 return;
04379
04380 for (x=0;x<5;x++) {
04381 y = ADSI_KEY_APPS + 12 + start + x;
04382 if (y > ADSI_KEY_APPS + 12 + 4)
04383 y = 0;
04384 keys[x] = ADSI_KEY_SKT | y;
04385 }
04386 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
04387 keys[6] = 0;
04388 keys[7] = 0;
04389
04390 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
04391 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
04392 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04393 bytes += ast_adsi_set_keys(buf + bytes, keys);
04394 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04395
04396 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04397 }
04398
04399 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
04400 {
04401 int bytes=0;
04402 unsigned char buf[256];
04403 char buf1[256], buf2[256];
04404 char fn2[PATH_MAX];
04405
04406 char cid[256]="";
04407 char *val;
04408 char *name, *num;
04409 char datetime[21]="";
04410 FILE *f;
04411
04412 unsigned char keys[8];
04413
04414 int x;
04415
04416 if (!ast_adsi_available(chan))
04417 return;
04418
04419
04420 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
04421 f = fopen(fn2, "r");
04422 if (f) {
04423 while (!feof(f)) {
04424 fgets((char *)buf, sizeof(buf), f);
04425 if (!feof(f)) {
04426 char *stringp=NULL;
04427 stringp = (char *)buf;
04428 strsep(&stringp, "=");
04429 val = strsep(&stringp, "=");
04430 if (!ast_strlen_zero(val)) {
04431 if (!strcmp((char *)buf, "callerid"))
04432 ast_copy_string(cid, val, sizeof(cid));
04433 if (!strcmp((char *)buf, "origdate"))
04434 ast_copy_string(datetime, val, sizeof(datetime));
04435 }
04436 }
04437 }
04438 fclose(f);
04439 }
04440
04441 for (x=0;x<5;x++)
04442 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
04443 keys[6] = 0x0;
04444 keys[7] = 0x0;
04445
04446 if (!vms->curmsg) {
04447
04448 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
04449 }
04450 if (vms->curmsg >= vms->lastmsg) {
04451
04452 if (vms->curmsg) {
04453
04454 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
04455 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04456
04457 } else {
04458
04459 keys[3] = 1;
04460 }
04461 }
04462
04463 if (!ast_strlen_zero(cid)) {
04464 ast_callerid_parse(cid, &name, &num);
04465 if (!name)
04466 name = num;
04467 } else
04468 name = "Unknown Caller";
04469
04470
04471
04472 if (vms->deleted[vms->curmsg])
04473 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
04474
04475
04476 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
04477 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
04478 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
04479 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
04480
04481 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
04482 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
04483 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
04484 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
04485 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04486 bytes += ast_adsi_set_keys(buf + bytes, keys);
04487 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04488
04489 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04490 }
04491
04492 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
04493 {
04494 int bytes=0;
04495 unsigned char buf[256];
04496 unsigned char keys[8];
04497
04498 int x;
04499
04500 if (!ast_adsi_available(chan))
04501 return;
04502
04503
04504 for (x=0;x<5;x++)
04505 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
04506
04507 keys[6] = 0x0;
04508 keys[7] = 0x0;
04509
04510 if (!vms->curmsg) {
04511
04512 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
04513 }
04514 if (vms->curmsg >= vms->lastmsg) {
04515
04516 if (vms->curmsg) {
04517
04518 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
04519 } else {
04520
04521 keys[3] = 1;
04522 }
04523 }
04524
04525
04526 if (vms->deleted[vms->curmsg])
04527 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
04528
04529
04530 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
04531 bytes += ast_adsi_set_keys(buf + bytes, keys);
04532 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04533
04534 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04535 }
04536
04537 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
04538 {
04539 unsigned char buf[256] = "";
04540 char buf1[256] = "", buf2[256] = "";
04541 int bytes=0;
04542 unsigned char keys[8];
04543 int x;
04544
04545 char *newm = (vms->newmessages == 1) ? "message" : "messages";
04546 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
04547 if (!ast_adsi_available(chan))
04548 return;
04549 if (vms->newmessages) {
04550 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
04551 if (vms->oldmessages) {
04552 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
04553 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
04554 } else {
04555 snprintf(buf2, sizeof(buf2), "%s.", newm);
04556 }
04557 } else if (vms->oldmessages) {
04558 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
04559 snprintf(buf2, sizeof(buf2), "%s.", oldm);
04560 } else {
04561 strcpy(buf1, "You have no messages.");
04562 buf2[0] = ' ';
04563 buf2[1] = '\0';
04564 }
04565 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
04566 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
04567 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04568
04569 for (x=0;x<6;x++)
04570 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
04571 keys[6] = 0;
04572 keys[7] = 0;
04573
04574
04575 if (vms->lastmsg < 0)
04576 keys[0] = 1;
04577 bytes += ast_adsi_set_keys(buf + bytes, keys);
04578
04579 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04580
04581 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04582 }
04583
04584 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
04585 {
04586 unsigned char buf[256] = "";
04587 char buf1[256] = "", buf2[256] = "";
04588 int bytes=0;
04589 unsigned char keys[8];
04590 int x;
04591
04592 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
04593
04594 if (!ast_adsi_available(chan))
04595 return;
04596
04597
04598 for (x=0;x<6;x++)
04599 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
04600
04601 keys[6] = 0;
04602 keys[7] = 0;
04603
04604 if ((vms->lastmsg + 1) < 1)
04605 keys[0] = 0;
04606
04607 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
04608 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
04609
04610 if (vms->lastmsg + 1)
04611 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
04612 else
04613 strcpy(buf2, "no messages.");
04614 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
04615 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
04616 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
04617 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04618 bytes += ast_adsi_set_keys(buf + bytes, keys);
04619
04620 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04621
04622 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04623
04624 }
04625
04626
04627
04628
04629
04630
04631
04632
04633
04634
04635
04636
04637
04638
04639
04640 static void adsi_goodbye(struct ast_channel *chan)
04641 {
04642 unsigned char buf[256];
04643 int bytes=0;
04644
04645 if (!ast_adsi_available(chan))
04646 return;
04647 bytes += adsi_logo(buf + bytes);
04648 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
04649 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
04650 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
04651 bytes += ast_adsi_voice_mode(buf + bytes, 0);
04652
04653 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
04654 }
04655
04656
04657
04658
04659
04660 static int get_folder(struct ast_channel *chan, int start)
04661 {
04662 int x;
04663 int d;
04664 char fn[PATH_MAX];
04665 d = ast_play_and_wait(chan, "vm-press");
04666 if (d)
04667 return d;
04668 for (x = start; x< 5; x++) {
04669 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, (char *) NULL)))
04670 return d;
04671 d = ast_play_and_wait(chan, "vm-for");
04672 if (d)
04673 return d;
04674 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
04675 d = vm_play_folder_name(chan, fn);
04676 if (d)
04677 return d;
04678 d = ast_waitfordigit(chan, 500);
04679 if (d)
04680 return d;
04681 }
04682 d = ast_play_and_wait(chan, "vm-tocancel");
04683 if (d)
04684 return d;
04685 d = ast_waitfordigit(chan, 4000);
04686 return d;
04687 }
04688
04689 static int get_folder2(struct ast_channel *chan, char *fn, int start)
04690 {
04691 int res = 0;
04692 res = ast_play_and_wait(chan, fn);
04693 while (((res < '0') || (res > '9')) &&
04694 (res != '#') && (res >= 0)) {
04695 res = get_folder(chan, 0);
04696 }
04697 return res;
04698 }
04699
04700 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vmfmts,
04701 char *context, signed char record_gain, long *duration, struct vm_state *vms)
04702 {
04703 int cmd = 0;
04704 int retries = 0, prepend_duration = 0, already_recorded = 0;
04705 signed char zero_gain = 0;
04706 struct ast_config *msg_cfg;
04707 const char *duration_str;
04708 char msgfile[PATH_MAX], backup[PATH_MAX];
04709 char textfile[PATH_MAX];
04710
04711
04712 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
04713 strcpy(textfile, msgfile);
04714 strcpy(backup, msgfile);
04715 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
04716 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
04717
04718 if (!(msg_cfg = ast_config_load(textfile))) {
04719 return -1;
04720 }
04721
04722 *duration = 0;
04723 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
04724 *duration = atoi(duration_str);
04725
04726 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
04727 if (cmd)
04728 retries = 0;
04729 switch (cmd) {
04730 case '1':
04731
04732 {
04733 prepend_duration = 0;
04734
04735
04736 if (!msg_cfg) {
04737 cmd = 0;
04738 break;
04739 }
04740
04741
04742 if (already_recorded)
04743 ast_filecopy(backup, msgfile, NULL);
04744 else
04745 ast_filecopy(msgfile, backup, NULL);
04746 already_recorded = 1;
04747
04748 if (record_gain)
04749 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
04750
04751 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vmfmts, &prepend_duration, 1, silencethreshold, maxsilence);
04752 if (record_gain)
04753 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
04754
04755 if (prepend_duration) {
04756 struct ast_category *msg_cat;
04757
04758 char duration_str[12];
04759
04760 prepend_duration += *duration;
04761 msg_cat = ast_category_get(msg_cfg, "message");
04762 snprintf(duration_str, 11, "%d", prepend_duration);
04763 if (!ast_variable_update(msg_cat, "duration", duration_str, NULL, 0)) {
04764 config_text_file_save(textfile, msg_cfg, "app_voicemail");
04765 }
04766 }
04767
04768 break;
04769 }
04770 case '2':
04771 cmd = 't';
04772 break;
04773 case '*':
04774 cmd = '*';
04775 break;
04776 default:
04777 cmd = ast_play_and_wait(chan,"vm-forwardoptions");
04778
04779 if (!cmd)
04780 cmd = ast_play_and_wait(chan,"vm-starmain");
04781
04782 if (!cmd)
04783 cmd = ast_waitfordigit(chan,6000);
04784 if (!cmd)
04785 retries++;
04786 if (retries > 3)
04787 cmd = 't';
04788 }
04789 }
04790
04791 ast_config_destroy(msg_cfg);
04792 if (already_recorded)
04793 ast_filedelete(backup, NULL);
04794 if (prepend_duration)
04795 *duration = prepend_duration;
04796
04797 if (cmd == 't' || cmd == 'S')
04798 cmd = 0;
04799 return cmd;
04800 }
04801
04802 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname)
04803 {
04804 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
04805 int newmsgs = 0, oldmsgs = 0;
04806 const char *category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
04807
04808 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX");
04809 make_file(fn, sizeof(fn), todir, msgnum);
04810 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
04811
04812 if (!ast_strlen_zero(vmu->attachfmt)) {
04813 if (strstr(fmt, vmu->attachfmt)) {
04814 fmt = vmu->attachfmt;
04815 } else {
04816 ast_log(LOG_WARNING, "Attachment format '%s' is not one of the recorded formats '%s'. Falling back to default format for '%s@%s'.\n", vmu->attachfmt, fmt, vmu->mailbox, vmu->context);
04817 }
04818 }
04819
04820
04821 fmt = ast_strdupa(fmt);
04822 stringp = fmt;
04823 strsep(&stringp, "|");
04824
04825 if (!ast_strlen_zero(vmu->email)) {
04826 int attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH);
04827 char *myserveremail = serveremail;
04828 attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
04829 if (!ast_strlen_zero(vmu->serveremail))
04830 myserveremail = vmu->serveremail;
04831
04832 if (attach_user_voicemail)
04833 RETRIEVE(todir, msgnum, vmu);
04834
04835
04836 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, fn, fmt, duration, attach_user_voicemail, chan, category);
04837
04838 if (attach_user_voicemail)
04839 DISPOSE(todir, msgnum);
04840 }
04841
04842 if (!ast_strlen_zero(vmu->pager)) {
04843 char *myserveremail = serveremail;
04844 if (!ast_strlen_zero(vmu->serveremail))
04845 myserveremail = vmu->serveremail;
04846 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, duration, vmu, category);
04847 }
04848
04849 if (ast_test_flag(vmu, VM_DELETE)) {
04850 DELETE(todir, msgnum, fn, vmu);
04851 }
04852
04853
04854 if (ast_app_has_voicemail(ext_context, NULL)) {
04855 ast_app_inboxcount(ext_context, &newmsgs, &oldmsgs);
04856 }
04857 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s@%s\r\nWaiting: %d\r\nNew: %d\r\nOld: %d\r\n", vmu->mailbox, vmu->context, ast_app_has_voicemail(ext_context, NULL), newmsgs, oldmsgs);
04858 run_externnotify(vmu->context, vmu->mailbox);
04859 return 0;
04860 }
04861
04862 static int forward_message(struct ast_channel *chan, char *context, struct vm_state *vms, struct ast_vm_user *sender, char *fmt, int flag, signed char record_gain)
04863 {
04864 #ifdef IMAP_STORAGE
04865 int todircount=0;
04866 struct vm_state *dstvms;
04867 #endif
04868 char username[70]="";
04869 int res = 0, cmd = 0;
04870 struct ast_vm_user *receiver = NULL, *vmtmp;
04871 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
04872 char *stringp;
04873 const char *s;
04874 int saved_messages = 0, found = 0;
04875 int valid_extensions = 0;
04876 char *dir;
04877 int curmsg;
04878
04879 if (vms == NULL) return -1;
04880 dir = vms->curdir;
04881 curmsg = vms->curmsg;
04882
04883 while (!res && !valid_extensions) {
04884 int use_directory = 0;
04885 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
04886 int done = 0;
04887 int retries = 0;
04888 cmd=0;
04889 while ((cmd >= 0) && !done ){
04890 if (cmd)
04891 retries = 0;
04892 switch (cmd) {
04893 case '1':
04894 use_directory = 0;
04895 done = 1;
04896 break;
04897 case '2':
04898 use_directory = 1;
04899 done=1;
04900 break;
04901 case '*':
04902 cmd = 't';
04903 done = 1;
04904 break;
04905 default:
04906
04907 cmd = ast_play_and_wait(chan,"vm-forward");
04908 if (!cmd)
04909 cmd = ast_waitfordigit(chan,3000);
04910 if (!cmd)
04911 retries++;
04912 if (retries > 3)
04913 {
04914 cmd = 't';
04915 done = 1;
04916 }
04917
04918 }
04919 }
04920 if (cmd < 0 || cmd == 't')
04921 break;
04922 }
04923
04924 if (use_directory) {
04925
04926
04927 char old_context[sizeof(chan->context)];
04928 char old_exten[sizeof(chan->exten)];
04929 int old_priority;
04930 struct ast_app* app;
04931
04932
04933 app = pbx_findapp("Directory");
04934 if (app) {
04935 char vmcontext[256];
04936
04937 memcpy(old_context, chan->context, sizeof(chan->context));
04938 memcpy(old_exten, chan->exten, sizeof(chan->exten));
04939 old_priority = chan->priority;
04940
04941
04942 snprintf(vmcontext, sizeof(vmcontext), "%s||v", context ? context : "default");
04943 res = pbx_exec(chan, app, vmcontext);
04944
04945 ast_copy_string(username, chan->exten, sizeof(username));
04946
04947
04948 memcpy(chan->context, old_context, sizeof(chan->context));
04949 memcpy(chan->exten, old_exten, sizeof(chan->exten));
04950 chan->priority = old_priority;
04951
04952 } else {
04953 ast_log(LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
04954 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
04955 }
04956 } else {
04957
04958 res = ast_streamfile(chan, "vm-extension", chan->language);
04959 if (res)
04960 break;
04961 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
04962 break;
04963 }
04964
04965
04966 if (ast_strlen_zero(username))
04967 continue;
04968 stringp = username;
04969 s = strsep(&stringp, "*");
04970
04971 valid_extensions = 1;
04972 while (s) {
04973
04974 if ((flag == 1 || strcmp(s,sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
04975 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
04976 found++;
04977 } else {
04978 valid_extensions = 0;
04979 break;
04980 }
04981 s = strsep(&stringp, "*");
04982 }
04983
04984 if (valid_extensions)
04985 break;
04986
04987 res = ast_play_and_wait(chan, "pbx-invalid");
04988 }
04989
04990 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
04991 return res;
04992 if (flag==1) {
04993 struct leave_vm_options leave_options;
04994 char mailbox[AST_MAX_EXTENSION * 2 + 2];
04995
04996 if (context)
04997 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
04998 else
04999 ast_copy_string(mailbox, username, sizeof(mailbox));
05000
05001
05002 memset(&leave_options, 0, sizeof(leave_options));
05003 leave_options.record_gain = record_gain;
05004 cmd = leave_voicemail(chan, mailbox, &leave_options);
05005 } else {
05006
05007 long duration = 0;
05008 char origmsgfile[PATH_MAX], msgfile[PATH_MAX];
05009 struct vm_state vmstmp;
05010
05011 memcpy(&vmstmp, vms, sizeof(vmstmp));
05012
05013 make_file(origmsgfile, sizeof(origmsgfile), dir, curmsg);
05014 create_dirpath(vmstmp.curdir, sizeof(vmstmp.curdir), sender->context, vmstmp.username, "tmp");
05015 make_file(msgfile, sizeof(msgfile), vmstmp.curdir, curmsg);
05016
05017 RETRIEVE(dir, curmsg, sender);
05018
05019
05020 copy_plain_file(origmsgfile, msgfile);
05021
05022 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp);
05023 if (!cmd) {
05024 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
05025 #ifdef IMAP_STORAGE
05026 char *myserveremail;
05027 int attach_user_voicemail;
05028
05029 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
05030 if (!dstvms) {
05031 dstvms = create_vm_state_from_user(vmtmp);
05032 }
05033 if (dstvms) {
05034 init_mailstream(dstvms, 0);
05035 if (!dstvms->mailstream) {
05036 ast_log (LOG_ERROR,"IMAP mailstream for %s is NULL\n",vmtmp->mailbox);
05037 } else {
05038 STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms);
05039 run_externnotify(vmtmp->context, vmtmp->mailbox);
05040 }
05041 } else {
05042 ast_log (LOG_ERROR,"Could not find state information for mailbox %s\n",vmtmp->mailbox);
05043 }
05044 myserveremail = serveremail;
05045 if (!ast_strlen_zero(vmtmp->serveremail))
05046 myserveremail = vmtmp->serveremail;
05047 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
05048
05049 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), vms->fn, fmt, duration, attach_user_voicemail, chan, NULL);
05050 #else
05051 copy_message(chan, sender, -1, curmsg, duration, vmtmp, fmt, vmstmp.curdir);
05052 #endif
05053 saved_messages++;
05054 AST_LIST_REMOVE_CURRENT(&extensions, list);
05055 free_user(vmtmp);
05056 if (res)
05057 break;
05058 }
05059 AST_LIST_TRAVERSE_SAFE_END;
05060 if (saved_messages > 0) {
05061
05062
05063
05064
05065
05066
05067
05068
05069 res = ast_play_and_wait(chan, "vm-msgsaved");
05070 }
05071 }
05072
05073
05074 vm_delete(msgfile);
05075 DISPOSE(dir, curmsg);
05076 }
05077
05078
05079 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list)))
05080 free_user(vmtmp);
05081 return res ? res : cmd;
05082 }
05083
05084 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
05085 {
05086 int res;
05087 if ((res = ast_stream_and_wait(chan, file, chan->language, AST_DIGIT_ANY)) < 0)
05088 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
05089 return res;
05090 }
05091
05092 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
05093 {
05094 return ast_control_streamfile(chan, file, "#", "*", "1456789", "0", "2", skipms);
05095 }
05096
05097 static int play_message_category(struct ast_channel *chan, const char *category)
05098 {
05099 int res = 0;
05100
05101 if (!ast_strlen_zero(category))
05102 res = ast_play_and_wait(chan, category);
05103
05104 if (res) {
05105 ast_log(LOG_WARNING, "No sound file for category '%s' was found.\n", category);
05106 res = 0;
05107 }
05108
05109 return res;
05110 }
05111
05112 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
05113 {
05114 int res = 0;
05115 struct vm_zone *the_zone = NULL;
05116 time_t t;
05117
05118 if (ast_get_time_t(origtime, &t, 0, NULL)) {
05119 ast_log(LOG_WARNING, "Couldn't find origtime in %s\n", filename);
05120 return 0;
05121 }
05122
05123
05124 if (!ast_strlen_zero(vmu->zonetag)) {
05125
05126 struct vm_zone *z;
05127 AST_LIST_LOCK(&zones);
05128 AST_LIST_TRAVERSE(&zones, z, list) {
05129 if (!strcmp(z->name, vmu->zonetag)) {
05130 the_zone = z;
05131 break;
05132 }
05133 }
05134 AST_LIST_UNLOCK(&zones);
05135 }
05136
05137
05138 #if 0
05139
05140 ast_localtime(&t, &time_now, NULL);
05141 tv_now = ast_tvnow();
05142 tnow = tv_now.tv_sec;
05143 ast_localtime(&tnow, &time_then, NULL);
05144
05145
05146 if (time_now.tm_year == time_then.tm_year)
05147 snprintf(temp,sizeof(temp),"%d",time_now.tm_yday);
05148 else
05149 snprintf(temp,sizeof(temp),"%d",(time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
05150 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
05151
05152
05153 #endif
05154 if (the_zone)
05155 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
05156 else if (!strncasecmp(chan->language,"pl",2))
05157 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
05158 else if (!strncasecmp(chan->language,"se",2))
05159 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
05160 else if (!strncasecmp(chan->language,"no",2))
05161 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
05162 else if (!strncasecmp(chan->language,"de",2))
05163 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
05164 else if (!strncasecmp(chan->language,"nl",2))
05165 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
05166 else if (!strncasecmp(chan->language,"it",2))
05167 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' 'digits/hours' k 'digits/e' M 'digits/minutes'", NULL);
05168 else if (!strncasecmp(chan->language,"gr",2))
05169 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
05170 else if (!strcasecmp(chan->language,"pt_BR"))
05171 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Ad 'digits/pt-de' B 'digits/pt-de' Y 'digits/pt-as' HM ", NULL);
05172 else
05173 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
05174 #if 0
05175 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
05176 #endif
05177 return res;
05178 }
05179
05180
05181
05182 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
05183 {
05184 int res = 0;
05185 int i;
05186 char *callerid, *name;
05187 char prefile[PATH_MAX] = "";
05188
05189
05190
05191
05192 if ((cid == NULL)||(context == NULL))
05193 return res;
05194
05195
05196 if (option_debug > 2)
05197 ast_log(LOG_DEBUG, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
05198 ast_callerid_parse(cid, &name, &callerid);
05199 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
05200
05201
05202 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
05203 if (option_debug > 2)
05204 ast_log(LOG_DEBUG, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
05205 if ((strcmp(cidinternalcontexts[i], context) == 0))
05206 break;
05207 }
05208 if (i != MAX_NUM_CID_CONTEXTS){
05209 if (!res) {
05210 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
05211 if (!ast_strlen_zero(prefile)) {
05212
05213 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05214 if (option_verbose > 2)
05215 ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
05216 if (!callback)
05217 res = wait_file2(chan, vms, "vm-from");
05218 res = ast_stream_and_wait(chan, prefile, chan->language, "");
05219 } else {
05220 if (option_verbose > 2)
05221 ast_verbose(VERBOSE_PREFIX_3 "Playing envelope info: message from '%s'\n", callerid);
05222
05223 if (!callback)
05224 res = wait_file2(chan, vms, "vm-from-extension");
05225 res = ast_say_digit_str(chan, callerid, "", chan->language);
05226 }
05227 }
05228 }
05229 }
05230
05231 else if (!res){
05232 if (option_debug > 2)
05233 ast_log(LOG_DEBUG, "VM-CID: Numeric caller id: (%s)\n",callerid);
05234
05235 if (!callback)
05236 res = wait_file2(chan, vms, "vm-from-phonenumber");
05237 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
05238 }
05239 } else {
05240
05241 if (option_debug)
05242 ast_log(LOG_DEBUG, "VM-CID: From an unknown number\n");
05243
05244 res = wait_file2(chan, vms, "vm-unknown-caller");
05245 }
05246 return res;
05247 }
05248
05249 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
05250 {
05251 int res = 0;
05252 int durationm;
05253 int durations;
05254
05255 if (duration == NULL)
05256 return res;
05257
05258
05259 durations=atoi(duration);
05260 durationm=(durations / 60);
05261
05262 if (option_debug > 2)
05263 ast_log(LOG_DEBUG, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
05264
05265 if ((!res) && (durationm >= minduration)) {
05266 res = wait_file2(chan, vms, "vm-duration");
05267
05268
05269 if (!strncasecmp(chan->language, "pl",2)) {
05270 div_t num = div(durationm, 10);
05271
05272 if (durationm == 1) {
05273 res = ast_play_and_wait(chan, "digits/1z");
05274 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
05275 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
05276 if (num.rem == 2) {
05277 if (!num.quot) {
05278 res = ast_play_and_wait(chan, "digits/2-ie");
05279 } else {
05280 res = say_and_wait(chan, durationm - 2 , chan->language);
05281 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
05282 }
05283 } else {
05284 res = say_and_wait(chan, durationm, chan->language);
05285 }
05286 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
05287 } else {
05288 res = say_and_wait(chan, durationm, chan->language);
05289 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
05290 }
05291
05292 } else {
05293 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
05294 res = wait_file2(chan, vms, "vm-minutes");
05295 }
05296 }
05297 return res;
05298 }
05299
05300 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
05301 {
05302 int res = 0;
05303 char filename[256], *cid;
05304 const char *origtime, *context, *category, *duration;
05305 struct ast_config *msg_cfg;
05306
05307 vms->starting = 0;
05308 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
05309 adsi_message(chan, vms);
05310 if (!vms->curmsg)
05311 res = wait_file2(chan, vms, "vm-first");
05312 else if (vms->curmsg == vms->lastmsg)
05313 res = wait_file2(chan, vms, "vm-last");
05314 if (!res) {
05315
05316 if (!strncasecmp(chan->language, "pl",2)) {
05317 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
05318 int ten, one;
05319 char nextmsg[256];
05320 ten = (vms->curmsg + 1) / 10;
05321 one = (vms->curmsg + 1) % 10;
05322
05323 if (vms->curmsg < 20) {
05324 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
05325 res = wait_file2(chan, vms, nextmsg);
05326 } else {
05327 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
05328 res = wait_file2(chan, vms, nextmsg);
05329 if (one > 0) {
05330 if (!res) {
05331 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
05332 res = wait_file2(chan, vms, nextmsg);
05333 }
05334 }
05335 }
05336 }
05337 if (!res)
05338 res = wait_file2(chan, vms, "vm-message");
05339 } else {
05340 if (!strncasecmp(chan->language,"se",2))
05341 res = wait_file2(chan, vms, "vm-meddelandet");
05342 else
05343 res = wait_file2(chan, vms, "vm-message");
05344 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
05345 if (!res)
05346 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
05347 }
05348 }
05349 }
05350
05351
05352 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
05353 snprintf(filename, sizeof(filename), "%s.txt", vms->fn2);
05354 RETRIEVE(vms->curdir, vms->curmsg, vmu);
05355 msg_cfg = ast_config_load(filename);
05356 if (!msg_cfg) {
05357 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
05358 return 0;
05359 }
05360
05361 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
05362 ast_log(LOG_WARNING, "No origtime?!\n");
05363 DISPOSE(vms->curdir, vms->curmsg);
05364 ast_config_destroy(msg_cfg);
05365 return 0;
05366 }
05367
05368 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
05369 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
05370 category = ast_variable_retrieve(msg_cfg, "message", "category");
05371
05372 context = ast_variable_retrieve(msg_cfg, "message", "context");
05373 if (!strncasecmp("macro",context,5))
05374 context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
05375 if (!res)
05376 res = play_message_category(chan, category);
05377 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE)))
05378 res = play_message_datetime(chan, vmu, origtime, filename);
05379 if ((!res) && (ast_test_flag(vmu, VM_SAYCID)))
05380 res = play_message_callerid(chan, vms, cid, context, 0);
05381 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION)))
05382 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
05383
05384 if (res == '1')
05385 res = 0;
05386 ast_config_destroy(msg_cfg);
05387
05388 if (!res) {
05389 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
05390 vms->heard[vms->curmsg] = 1;
05391 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
05392 ast_log(LOG_WARNING, "Playback of message %s failed\n", vms->fn);
05393 res = 0;
05394 }
05395 }
05396 DISPOSE(vms->curdir, vms->curmsg);
05397 return res;
05398 }
05399
05400 #ifndef IMAP_STORAGE
05401 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu,int box)
05402 {
05403 int res = 0;
05404 int count_msg, last_msg;
05405
05406 ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
05407
05408
05409
05410
05411 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
05412
05413
05414 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
05415
05416 count_msg = count_messages(vmu, vms->curdir);
05417 if (count_msg < 0)
05418 return count_msg;
05419 else
05420 vms->lastmsg = count_msg - 1;
05421
05422
05423
05424
05425
05426
05427
05428
05429 last_msg = last_message_index(vmu, vms->curdir);
05430 if (last_msg < 0)
05431 return last_msg;
05432 else if (vms->lastmsg != last_msg)
05433 {
05434 ast_log(LOG_NOTICE, "Resequencing Mailbox: %s\n", vms->curdir);
05435 res = resequence_mailbox(vmu, vms->curdir);
05436 if (res)
05437 return res;
05438 }
05439
05440 return 0;
05441 }
05442 #endif
05443
05444 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
05445 {
05446 int x = 0;
05447 #ifndef IMAP_STORAGE
05448 int res = 0, nummsg;
05449 #endif
05450
05451 if (vms->lastmsg <= -1)
05452 goto done;
05453
05454 vms->curmsg = -1;
05455 #ifndef IMAP_STORAGE
05456
05457 if (vm_lock_path(vms->curdir))
05458 return ERROR_LOCK_PATH;
05459
05460 for (x = 0; x < vmu->maxmsg; x++) {
05461 if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) {
05462
05463 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
05464 if (!EXISTS(vms->curdir, x, vms->fn, NULL))
05465 break;
05466 vms->curmsg++;
05467 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
05468 if (strcmp(vms->fn, vms->fn2)) {
05469 RENAME(vms->curdir, x, vmu->mailbox,vmu->context, vms->curdir, vms->curmsg, vms->fn, vms->fn2);
05470 }
05471 } else if (!strcasecmp(vms->curbox, "INBOX") && vms->heard[x] && !vms->deleted[x]) {
05472
05473 res = save_to_folder(vmu, vms, x, 1);
05474 if (res == ERROR_LOCK_PATH || res == ERROR_MAILBOX_FULL) {
05475
05476 ast_log(LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
05477 vms->deleted[x] = 0;
05478 vms->heard[x] = 0;
05479 --x;
05480 }
05481 }
05482 }
05483
05484
05485 nummsg = x - 1;
05486 for (x = vms->curmsg + 1; x <= nummsg; x++) {
05487 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
05488 if (EXISTS(vms->curdir, x, vms->fn, NULL))
05489 DELETE(vms->curdir, x, vms->fn, vmu);
05490 }
05491 ast_unlock_path(vms->curdir);
05492 #else
05493 if (vms->deleted) {
05494 for (x=0;x < vmu->maxmsg;x++) {
05495 if (vms->deleted[x]) {
05496 if (option_debug > 2)
05497 ast_log(LOG_DEBUG,"IMAP delete of %d\n",x);
05498 DELETE(vms->curdir, x, vms->fn, vmu);
05499 }
05500 }
05501 }
05502 #endif
05503
05504 done:
05505 if (vms->deleted)
05506 memset(vms->deleted, 0, vmu->maxmsg * sizeof(int));
05507 if (vms->heard)
05508 memset(vms->heard, 0, vmu->maxmsg * sizeof(int));
05509
05510 return 0;
05511 }
05512
05513
05514
05515
05516
05517
05518
05519 static int vm_play_folder_name_gr(struct ast_channel *chan, char *mbox)
05520 {
05521 int cmd;
05522 char *buf;
05523
05524 buf = alloca(strlen(mbox)+2);
05525 strcpy(buf, mbox);
05526 strcat(buf,"s");
05527
05528 if (!strcasecmp(mbox, "vm-INBOX") || !strcasecmp(mbox, "vm-Old")){
05529 cmd = ast_play_and_wait(chan, buf);
05530 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
05531 } else {
05532 cmd = ast_play_and_wait(chan, "vm-messages");
05533 return cmd ? cmd : ast_play_and_wait(chan, mbox);
05534 }
05535 }
05536
05537 static int vm_play_folder_name_pl(struct ast_channel *chan, char *mbox)
05538 {
05539 int cmd;
05540
05541 if (!strcasecmp(mbox, "vm-INBOX") || !strcasecmp(mbox, "vm-Old")) {
05542 if (!strcasecmp(mbox, "vm-INBOX"))
05543 cmd = ast_play_and_wait(chan, "vm-new-e");
05544 else
05545 cmd = ast_play_and_wait(chan, "vm-old-e");
05546 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
05547 } else {
05548 cmd = ast_play_and_wait(chan, "vm-messages");
05549 return cmd ? cmd : ast_play_and_wait(chan, mbox);
05550 }
05551 }
05552
05553 static int vm_play_folder_name_ua(struct ast_channel *chan, char *mbox)
05554 {
05555 int cmd;
05556
05557 if (!strcasecmp(mbox, "vm-Family") || !strcasecmp(mbox, "vm-Friends") || !strcasecmp(mbox, "vm-Work")){
05558 cmd = ast_play_and_wait(chan, "vm-messages");
05559 return cmd ? cmd : ast_play_and_wait(chan, mbox);
05560 } else {
05561 cmd = ast_play_and_wait(chan, mbox);
05562 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
05563 }
05564 }
05565
05566 static int vm_play_folder_name(struct ast_channel *chan, char *mbox)
05567 {
05568 int cmd;
05569
05570 if (!strncasecmp(chan->language, "it", 2) || !strncasecmp(chan->language, "es", 2) || !strncasecmp(chan->language, "fr", 2) || !strncasecmp(chan->language, "pt", 2)) {
05571 cmd = ast_play_and_wait(chan, "vm-messages");
05572 return cmd ? cmd : ast_play_and_wait(chan, mbox);
05573 } else if (!strncasecmp(chan->language, "gr", 2)){
05574 return vm_play_folder_name_gr(chan, mbox);
05575 } else if (!strncasecmp(chan->language, "pl", 2)){
05576 return vm_play_folder_name_pl(chan, mbox);
05577 } else if (!strncasecmp(chan->language, "ua", 2)){
05578 return vm_play_folder_name_ua(chan, mbox);
05579 } else {
05580 cmd = ast_play_and_wait(chan, mbox);
05581 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
05582 }
05583 }
05584
05585
05586
05587
05588
05589
05590
05591
05592
05593
05594
05595
05596
05597 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
05598 {
05599 int res = 0;
05600
05601 if (vms->newmessages) {
05602 res = ast_play_and_wait(chan, "vm-youhave");
05603 if (!res)
05604 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
05605 if (!res) {
05606 if ((vms->newmessages == 1)) {
05607 res = ast_play_and_wait(chan, "vm-INBOX");
05608 if (!res)
05609 res = ast_play_and_wait(chan, "vm-message");
05610 } else {
05611 res = ast_play_and_wait(chan, "vm-INBOXs");
05612 if (!res)
05613 res = ast_play_and_wait(chan, "vm-messages");
05614 }
05615 }
05616 } else if (vms->oldmessages){
05617 res = ast_play_and_wait(chan, "vm-youhave");
05618 if (!res)
05619 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
05620 if ((vms->oldmessages == 1)){
05621 res = ast_play_and_wait(chan, "vm-Old");
05622 if (!res)
05623 res = ast_play_and_wait(chan, "vm-message");
05624 } else {
05625 res = ast_play_and_wait(chan, "vm-Olds");
05626 if (!res)
05627 res = ast_play_and_wait(chan, "vm-messages");
05628 }
05629 } else if (!vms->oldmessages && !vms->newmessages)
05630 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
05631 return res;
05632 }
05633
05634
05635 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
05636 {
05637 int res;
05638
05639
05640 res = ast_play_and_wait(chan, "vm-youhave");
05641 if (!res) {
05642 if (vms->newmessages) {
05643 res = say_and_wait(chan, vms->newmessages, chan->language);
05644 if (!res)
05645 res = ast_play_and_wait(chan, "vm-INBOX");
05646 if (vms->oldmessages && !res)
05647 res = ast_play_and_wait(chan, "vm-and");
05648 else if (!res) {
05649 if ((vms->newmessages == 1))
05650 res = ast_play_and_wait(chan, "vm-message");
05651 else
05652 res = ast_play_and_wait(chan, "vm-messages");
05653 }
05654
05655 }
05656 if (!res && vms->oldmessages) {
05657 res = say_and_wait(chan, vms->oldmessages, chan->language);
05658 if (!res)
05659 res = ast_play_and_wait(chan, "vm-Old");
05660 if (!res) {
05661 if (vms->oldmessages == 1)
05662 res = ast_play_and_wait(chan, "vm-message");
05663 else
05664 res = ast_play_and_wait(chan, "vm-messages");
05665 }
05666 }
05667 if (!res) {
05668 if (!vms->oldmessages && !vms->newmessages) {
05669 res = ast_play_and_wait(chan, "vm-no");
05670 if (!res)
05671 res = ast_play_and_wait(chan, "vm-messages");
05672 }
05673 }
05674 }
05675 return res;
05676 }
05677
05678
05679 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
05680 {
05681
05682 int res;
05683 if (!vms->oldmessages && !vms->newmessages)
05684 res = ast_play_and_wait(chan, "vm-no") ||
05685 ast_play_and_wait(chan, "vm-message");
05686 else
05687 res = ast_play_and_wait(chan, "vm-youhave");
05688 if (!res && vms->newmessages) {
05689 res = (vms->newmessages == 1) ?
05690 ast_play_and_wait(chan, "digits/un") ||
05691 ast_play_and_wait(chan, "vm-nuovo") ||
05692 ast_play_and_wait(chan, "vm-message") :
05693
05694 say_and_wait(chan, vms->newmessages, chan->language) ||
05695 ast_play_and_wait(chan, "vm-nuovi") ||
05696 ast_play_and_wait(chan, "vm-messages");
05697 if (!res && vms->oldmessages)
05698 res = ast_play_and_wait(chan, "vm-and");
05699 }
05700 if (!res && vms->oldmessages) {
05701 res = (vms->oldmessages == 1) ?
05702 ast_play_and_wait(chan, "digits/un") ||
05703 ast_play_and_wait(chan, "vm-vecchio") ||
05704 ast_play_and_wait(chan, "vm-message") :
05705
05706 say_and_wait(chan, vms->oldmessages, chan->language) ||
05707 ast_play_and_wait(chan, "vm-vecchi") ||
05708 ast_play_and_wait(chan, "vm-messages");
05709 }
05710 return res ? -1 : 0;
05711 }
05712
05713
05714 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
05715 {
05716
05717 int res;
05718 div_t num;
05719
05720 if (!vms->oldmessages && !vms->newmessages) {
05721 res = ast_play_and_wait(chan, "vm-no");
05722 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05723 return res;
05724 } else {
05725 res = ast_play_and_wait(chan, "vm-youhave");
05726 }
05727
05728 if (vms->newmessages) {
05729 num = div(vms->newmessages, 10);
05730 if (vms->newmessages == 1) {
05731 res = ast_play_and_wait(chan, "digits/1-a");
05732 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
05733 res = res ? res : ast_play_and_wait(chan, "vm-message");
05734 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
05735 if (num.rem == 2) {
05736 if (!num.quot) {
05737 res = ast_play_and_wait(chan, "digits/2-ie");
05738 } else {
05739 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
05740 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
05741 }
05742 } else {
05743 res = say_and_wait(chan, vms->newmessages, chan->language);
05744 }
05745 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
05746 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05747 } else {
05748 res = say_and_wait(chan, vms->newmessages, chan->language);
05749 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
05750 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05751 }
05752 if (!res && vms->oldmessages)
05753 res = ast_play_and_wait(chan, "vm-and");
05754 }
05755 if (!res && vms->oldmessages) {
05756 num = div(vms->oldmessages, 10);
05757 if (vms->oldmessages == 1) {
05758 res = ast_play_and_wait(chan, "digits/1-a");
05759 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
05760 res = res ? res : ast_play_and_wait(chan, "vm-message");
05761 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
05762 if (num.rem == 2) {
05763 if (!num.quot) {
05764 res = ast_play_and_wait(chan, "digits/2-ie");
05765 } else {
05766 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
05767 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
05768 }
05769 } else {
05770 res = say_and_wait(chan, vms->oldmessages, chan->language);
05771 }
05772 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
05773 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05774 } else {
05775 res = say_and_wait(chan, vms->oldmessages, chan->language);
05776 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
05777 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05778 }
05779 }
05780
05781 return res;
05782 }
05783
05784
05785 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
05786 {
05787
05788 int res;
05789
05790 res = ast_play_and_wait(chan, "vm-youhave");
05791 if (res)
05792 return res;
05793
05794 if (!vms->oldmessages && !vms->newmessages) {
05795 res = ast_play_and_wait(chan, "vm-no");
05796 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05797 return res;
05798 }
05799
05800 if (vms->newmessages) {
05801 if ((vms->newmessages == 1)) {
05802 res = ast_play_and_wait(chan, "digits/ett");
05803 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
05804 res = res ? res : ast_play_and_wait(chan, "vm-message");
05805 } else {
05806 res = say_and_wait(chan, vms->newmessages, chan->language);
05807 res = res ? res : ast_play_and_wait(chan, "vm-nya");
05808 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05809 }
05810 if (!res && vms->oldmessages)
05811 res = ast_play_and_wait(chan, "vm-and");
05812 }
05813 if (!res && vms->oldmessages) {
05814 if (vms->oldmessages == 1) {
05815 res = ast_play_and_wait(chan, "digits/ett");
05816 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
05817 res = res ? res : ast_play_and_wait(chan, "vm-message");
05818 } else {
05819 res = say_and_wait(chan, vms->oldmessages, chan->language);
05820 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
05821 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05822 }
05823 }
05824
05825 return res;
05826 }
05827
05828
05829 static int vm_intro_no(struct ast_channel *chan,struct vm_state *vms)
05830 {
05831
05832 int res;
05833
05834 res = ast_play_and_wait(chan, "vm-youhave");
05835 if (res)
05836 return res;
05837
05838 if (!vms->oldmessages && !vms->newmessages) {
05839 res = ast_play_and_wait(chan, "vm-no");
05840 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05841 return res;
05842 }
05843
05844 if (vms->newmessages) {
05845 if ((vms->newmessages == 1)) {
05846 res = ast_play_and_wait(chan, "digits/1");
05847 res = res ? res : ast_play_and_wait(chan, "vm-ny");
05848 res = res ? res : ast_play_and_wait(chan, "vm-message");
05849 } else {
05850 res = say_and_wait(chan, vms->newmessages, chan->language);
05851 res = res ? res : ast_play_and_wait(chan, "vm-nye");
05852 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05853 }
05854 if (!res && vms->oldmessages)
05855 res = ast_play_and_wait(chan, "vm-and");
05856 }
05857 if (!res && vms->oldmessages) {
05858 if (vms->oldmessages == 1) {
05859 res = ast_play_and_wait(chan, "digits/1");
05860 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
05861 res = res ? res : ast_play_and_wait(chan, "vm-message");
05862 } else {
05863 res = say_and_wait(chan, vms->oldmessages, chan->language);
05864 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
05865 res = res ? res : ast_play_and_wait(chan, "vm-messages");
05866 }
05867 }
05868
05869 return res;
05870 }
05871
05872
05873 static int vm_intro_de(struct ast_channel *chan,struct vm_state *vms)
05874 {
05875
05876 int res;
05877 res = ast_play_and_wait(chan, "vm-youhave");
05878 if (!res) {
05879 if (vms->newmessages) {
05880 if ((vms->newmessages == 1))
05881 res = ast_play_and_wait(chan, "digits/1F");
05882 else
05883 res = say_and_wait(chan, vms->newmessages, chan->language);
05884 if (!res)
05885 res = ast_play_and_wait(chan, "vm-INBOX");
05886 if (vms->oldmessages && !res)
05887 res = ast_play_and_wait(chan, "vm-and");
05888 else if (!res) {
05889 if ((vms->newmessages == 1))
05890 res = ast_play_and_wait(chan, "vm-message");
05891 else
05892 res = ast_play_and_wait(chan, "vm-messages");
05893 }
05894
05895 }
05896 if (!res && vms->oldmessages) {
05897 if (vms->oldmessages == 1)
05898 res = ast_play_and_wait(chan, "digits/1F");
05899 else
05900 res = say_and_wait(chan, vms->oldmessages, chan->language);
05901 if (!res)
05902 res = ast_play_and_wait(chan, "vm-Old");
05903 if (!res) {
05904 if (vms->oldmessages == 1)
05905 res = ast_play_and_wait(chan, "vm-message");
05906 else
05907 res = ast_play_and_wait(chan, "vm-messages");
05908 }
05909 }
05910 if (!res) {
05911 if (!vms->oldmessages && !vms->newmessages) {
05912 res = ast_play_and_wait(chan, "vm-no");
05913 if (!res)
05914 res = ast_play_and_wait(chan, "vm-messages");
05915 }
05916 }
05917 }
05918 return res;
05919 }
05920
05921
05922 static int vm_intro_es(struct ast_channel *chan,struct vm_state *vms)
05923 {
05924
05925 int res;
05926 if (!vms->oldmessages && !vms->newmessages) {
05927 res = ast_play_and_wait(chan, "vm-youhaveno");
05928 if (!res)
05929 res = ast_play_and_wait(chan, "vm-messages");
05930 } else {
05931 res = ast_play_and_wait(chan, "vm-youhave");
05932 }
05933 if (!res) {
05934 if (vms->newmessages) {
05935 if (!res) {
05936 if ((vms->newmessages == 1)) {
05937 res = ast_play_and_wait(chan, "digits/1M");
05938 if (!res)
05939 res = ast_play_and_wait(chan, "vm-message");
05940 if (!res)
05941 res = ast_play_and_wait(chan, "vm-INBOXs");
05942 } else {
05943 res = say_and_wait(chan, vms->newmessages, chan->language);
05944 if (!res)
05945 res = ast_play_and_wait(chan, "vm-messages");
05946 if (!res)
05947 res = ast_play_and_wait(chan, "vm-INBOX");
05948 }
05949 }
05950 if (vms->oldmessages && !res)
05951 res = ast_play_and_wait(chan, "vm-and");
05952 }
05953 if (vms->oldmessages) {
05954 if (!res) {
05955 if (vms->oldmessages == 1) {
05956 res = ast_play_and_wait(chan, "digits/1M");
05957 if (!res)
05958 res = ast_play_and_wait(chan, "vm-message");
05959 if (!res)
05960 res = ast_play_and_wait(chan, "vm-Olds");
05961 } else {
05962 res = say_and_wait(chan, vms->oldmessages, chan->language);
05963 if (!res)
05964 res = ast_play_and_wait(chan, "vm-messages");
05965 if (!res)
05966 res = ast_play_and_wait(chan, "vm-Old");
05967 }
05968 }
05969 }
05970 }
05971 return res;
05972 }
05973
05974
05975 static int vm_intro_pt_BR(struct ast_channel *chan,struct vm_state *vms) {
05976
05977 int res;
05978 if (!vms->oldmessages && !vms->newmessages) {
05979 res = ast_play_and_wait(chan, "vm-nomessages");
05980 return res;
05981 }
05982 else {
05983 res = ast_play_and_wait(chan, "vm-youhave");
05984 }
05985 if (vms->newmessages) {
05986 if (!res)
05987 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
05988 if ((vms->newmessages == 1)) {
05989 if (!res)
05990 res = ast_play_and_wait(chan, "vm-message");
05991 if (!res)
05992 res = ast_play_and_wait(chan, "vm-INBOXs");
05993 }
05994 else {
05995 if (!res)
05996 res = ast_play_and_wait(chan, "vm-messages");
05997 if (!res)
05998 res = ast_play_and_wait(chan, "vm-INBOX");
05999 }
06000 if (vms->oldmessages && !res)
06001 res = ast_play_and_wait(chan, "vm-and");
06002 }
06003 if (vms->oldmessages) {
06004 if (!res)
06005 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
06006 if (vms->oldmessages == 1) {
06007 if (!res)
06008 res = ast_play_and_wait(chan, "vm-message");
06009 if (!res)
06010 res = ast_play_and_wait(chan, "vm-Olds");
06011 }
06012 else {
06013 if (!res)
06014 res = ast_play_and_wait(chan, "vm-messages");
06015 if (!res)
06016 res = ast_play_and_wait(chan, "vm-Old");
06017 }
06018 }
06019 return res;
06020 }
06021
06022
06023 static int vm_intro_fr(struct ast_channel *chan,struct vm_state *vms)
06024 {
06025
06026 int res;
06027 res = ast_play_and_wait(chan, "vm-youhave");
06028 if (!res) {
06029 if (vms->newmessages) {
06030 res = say_and_wait(chan, vms->newmessages, chan->language);
06031 if (!res)
06032 res = ast_play_and_wait(chan, "vm-INBOX");
06033 if (vms->oldmessages && !res)
06034 res = ast_play_and_wait(chan, "vm-and");
06035 else if (!res) {
06036 if ((vms->newmessages == 1))
06037 res = ast_play_and_wait(chan, "vm-message");
06038 else
06039 res = ast_play_and_wait(chan, "vm-messages");
06040 }
06041
06042 }
06043 if (!res && vms->oldmessages) {
06044 res = say_and_wait(chan, vms->oldmessages, chan->language);
06045 if (!res)
06046 res = ast_play_and_wait(chan, "vm-Old");
06047 if (!res) {
06048 if (vms->oldmessages == 1)
06049 res = ast_play_and_wait(chan, "vm-message");
06050 else
06051 res = ast_play_and_wait(chan, "vm-messages");
06052 }
06053 }
06054 if (!res) {
06055 if (!vms->oldmessages && !vms->newmessages) {
06056 res = ast_play_and_wait(chan, "vm-no");
06057 if (!res)
06058 res = ast_play_and_wait(chan, "vm-messages");
06059 }
06060 }
06061 }
06062 return res;
06063 }
06064
06065
06066 static int vm_intro_nl(struct ast_channel *chan,struct vm_state *vms)
06067 {
06068
06069 int res;
06070 res = ast_play_and_wait(chan, "vm-youhave");
06071 if (!res) {
06072 if (vms->newmessages) {
06073 res = say_and_wait(chan, vms->newmessages, chan->language);
06074 if (!res) {
06075 if (vms->newmessages == 1)
06076 res = ast_play_and_wait(chan, "vm-INBOXs");
06077 else
06078 res = ast_play_and_wait(chan, "vm-INBOX");
06079 }
06080 if (vms->oldmessages && !res)
06081 res = ast_play_and_wait(chan, "vm-and");
06082 else if (!res) {
06083 if ((vms->newmessages == 1))
06084 res = ast_play_and_wait(chan, "vm-message");
06085 else
06086 res = ast_play_and_wait(chan, "vm-messages");
06087 }
06088
06089 }
06090 if (!res && vms->oldmessages) {
06091 res = say_and_wait(chan, vms->oldmessages, chan->language);
06092 if (!res) {
06093 if (vms->oldmessages == 1)
06094 res = ast_play_and_wait(chan, "vm-Olds");
06095 else
06096 res = ast_play_and_wait(chan, "vm-Old");
06097 }
06098 if (!res) {
06099 if (vms->oldmessages == 1)
06100 res = ast_play_and_wait(chan, "vm-message");
06101 else
06102 res = ast_play_and_wait(chan, "vm-messages");
06103 }
06104 }
06105 if (!res) {
06106 if (!vms->oldmessages && !vms->newmessages) {
06107 res = ast_play_and_wait(chan, "vm-no");
06108 if (!res)
06109 res = ast_play_and_wait(chan, "vm-messages");
06110 }
06111 }
06112 }
06113 return res;
06114 }
06115
06116
06117 static int vm_intro_pt(struct ast_channel *chan,struct vm_state *vms)
06118 {
06119
06120 int res;
06121 res = ast_play_and_wait(chan, "vm-youhave");
06122 if (!res) {
06123 if (vms->newmessages) {
06124 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
06125 if (!res) {
06126 if ((vms->newmessages == 1)) {
06127 res = ast_play_and_wait(chan, "vm-message");
06128 if (!res)
06129 res = ast_play_and_wait(chan, "vm-INBOXs");
06130 } else {
06131 res = ast_play_and_wait(chan, "vm-messages");
06132 if (!res)
06133 res = ast_play_and_wait(chan, "vm-INBOX");
06134 }
06135 }
06136 if (vms->oldmessages && !res)
06137 res = ast_play_and_wait(chan, "vm-and");
06138 }
06139 if (!res && vms->oldmessages) {
06140 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
06141 if (!res) {
06142 if (vms->oldmessages == 1) {
06143 res = ast_play_and_wait(chan, "vm-message");
06144 if (!res)
06145 res = ast_play_and_wait(chan, "vm-Olds");
06146 } else {
06147 res = ast_play_and_wait(chan, "vm-messages");
06148 if (!res)
06149 res = ast_play_and_wait(chan, "vm-Old");
06150 }
06151 }
06152 }
06153 if (!res) {
06154 if (!vms->oldmessages && !vms->newmessages) {
06155 res = ast_play_and_wait(chan, "vm-no");
06156 if (!res)
06157 res = ast_play_and_wait(chan, "vm-messages");
06158 }
06159 }
06160 }
06161 return res;
06162 }
06163
06164
06165
06166
06167
06168
06169
06170
06171
06172
06173
06174
06175
06176
06177
06178
06179
06180 static int vm_intro_cz(struct ast_channel *chan,struct vm_state *vms)
06181 {
06182 int res;
06183 res = ast_play_and_wait(chan, "vm-youhave");
06184 if (!res) {
06185 if (vms->newmessages) {
06186 if (vms->newmessages == 1) {
06187 res = ast_play_and_wait(chan, "digits/jednu");
06188 } else {
06189 res = say_and_wait(chan, vms->newmessages, chan->language);
06190 }
06191 if (!res) {
06192 if ((vms->newmessages == 1))
06193 res = ast_play_and_wait(chan, "vm-novou");
06194 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
06195 res = ast_play_and_wait(chan, "vm-nove");
06196 if (vms->newmessages > 4)
06197 res = ast_play_and_wait(chan, "vm-novych");
06198 }
06199 if (vms->oldmessages && !res)
06200 res = ast_play_and_wait(chan, "vm-and");
06201 else if (!res) {
06202 if ((vms->newmessages == 1))
06203 res = ast_play_and_wait(chan, "vm-zpravu");
06204 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
06205 res = ast_play_and_wait(chan, "vm-zpravy");
06206 if (vms->newmessages > 4)
06207 res = ast_play_and_wait(chan, "vm-zprav");
06208 }
06209 }
06210 if (!res && vms->oldmessages) {
06211 res = say_and_wait(chan, vms->oldmessages, chan->language);
06212 if (!res) {
06213 if ((vms->oldmessages == 1))
06214 res = ast_play_and_wait(chan, "vm-starou");
06215 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
06216 res = ast_play_and_wait(chan, "vm-stare");
06217 if (vms->oldmessages > 4)
06218 res = ast_play_and_wait(chan, "vm-starych");
06219 }
06220 if (!res) {
06221 if ((vms->oldmessages == 1))
06222 res = ast_play_and_wait(chan, "vm-zpravu");
06223 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
06224 res = ast_play_and_wait(chan, "vm-zpravy");
06225 if (vms->oldmessages > 4)
06226 res = ast_play_and_wait(chan, "vm-zprav");
06227 }
06228 }
06229 if (!res) {
06230 if (!vms->oldmessages && !vms->newmessages) {
06231 res = ast_play_and_wait(chan, "vm-no");
06232 if (!res)
06233 res = ast_play_and_wait(chan, "vm-zpravy");
06234 }
06235 }
06236 }
06237 return res;
06238 }
06239
06240 static int get_lastdigits(int num)
06241 {
06242 num %= 100;
06243 return (num < 20) ? num : num % 10;
06244 }
06245
06246 static int vm_intro_ru(struct ast_channel *chan,struct vm_state *vms)
06247 {
06248 int res;
06249 int lastnum = 0;
06250 int dcnum;
06251
06252 res = ast_play_and_wait(chan, "vm-youhave");
06253 if (!res && vms->newmessages) {
06254 lastnum = get_lastdigits(vms->newmessages);
06255 dcnum = vms->newmessages - lastnum;
06256 if (dcnum)
06257 res = say_and_wait(chan, dcnum, chan->language);
06258 if (!res && lastnum) {
06259 if (lastnum == 1)
06260 res = ast_play_and_wait(chan, "digits/odno");
06261 else
06262 res = say_and_wait(chan, lastnum, chan->language);
06263 }
06264
06265 if (!res)
06266 res = ast_play_and_wait(chan, (lastnum == 1) ? "vm-novoe" : "vm-novyh");
06267
06268 if (!res && vms->oldmessages)
06269 res = ast_play_and_wait(chan, "vm-and");
06270 }
06271
06272 if (!res && vms->oldmessages) {
06273 lastnum = get_lastdigits(vms->oldmessages);
06274 dcnum = vms->oldmessages - lastnum;
06275 if (dcnum)
06276 res = say_and_wait(chan, dcnum, chan->language);
06277 if (!res && lastnum) {
06278 if (lastnum == 1)
06279 res = ast_play_and_wait(chan, "digits/odno");
06280 else
06281 res = say_and_wait(chan, lastnum, chan->language);
06282 }
06283
06284 if (!res)
06285 res = ast_play_and_wait(chan, (lastnum == 1) ? "vm-staroe" : "vm-staryh");
06286 }
06287
06288 if (!res && !vms->newmessages && !vms->oldmessages) {
06289 lastnum = 0;
06290 res = ast_play_and_wait(chan, "vm-no");
06291 }
06292
06293 if (!res) {
06294 switch (lastnum) {
06295 case 1:
06296 res = ast_play_and_wait(chan, "vm-soobshenie");
06297 break;
06298 case 2:
06299 case 3:
06300 case 4:
06301 res = ast_play_and_wait(chan, "vm-soobsheniya");
06302 break;
06303 default:
06304 res = ast_play_and_wait(chan, "vm-soobsheniy");
06305 break;
06306 }
06307 }
06308
06309 return res;
06310 }
06311
06312
06313
06314
06315
06316
06317
06318
06319
06320 static int vm_intro_ua(struct ast_channel *chan,struct vm_state *vms)
06321 {
06322 int res;
06323 int lastnum = 0;
06324 int dcnum;
06325
06326 res = ast_play_and_wait(chan, "vm-youhave");
06327 if (!res && vms->newmessages) {
06328 lastnum = get_lastdigits(vms->newmessages);
06329 dcnum = vms->newmessages - lastnum;
06330 if (dcnum)
06331 res = say_and_wait(chan, dcnum, chan->language);
06332 if (!res && lastnum) {
06333 if (lastnum == 1)
06334 res = ast_play_and_wait(chan, "digits/ua/1e");
06335 else
06336 res = say_and_wait(chan, lastnum, chan->language);
06337 }
06338
06339 if (!res)
06340 res = ast_play_and_wait(chan, (lastnum == 1) ? "vm-nove" : "vm-INBOX");
06341
06342 if (!res && vms->oldmessages)
06343 res = ast_play_and_wait(chan, "vm-and");
06344 }
06345
06346 if (!res && vms->oldmessages) {
06347 lastnum = get_lastdigits(vms->oldmessages);
06348 dcnum = vms->oldmessages - lastnum;
06349 if (dcnum)
06350 res = say_and_wait(chan, dcnum, chan->language);
06351 if (!res && lastnum) {
06352 if (lastnum == 1)
06353 res = ast_play_and_wait(chan, "digits/ua/1e");
06354 else
06355 res = say_and_wait(chan, lastnum, chan->language);
06356 }
06357
06358 if (!res)
06359 res = ast_play_and_wait(chan, (lastnum == 1) ? "vm-stare" : "vm-Old");
06360 }
06361
06362 if (!res && !vms->newmessages && !vms->oldmessages) {
06363 lastnum = 0;
06364 res = ast_play_and_wait(chan, "vm-no");
06365 }
06366
06367 if (!res) {
06368 switch (lastnum) {
06369 case 1:
06370 case 2:
06371 case 3:
06372 case 4:
06373 res = ast_play_and_wait(chan, "vm-message");
06374 break;
06375 default:
06376 res = ast_play_and_wait(chan, "vm-messages");
06377 break;
06378 }
06379 }
06380
06381 return res;
06382 }
06383
06384
06385 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
06386 {
06387 char prefile[256];
06388
06389
06390 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
06391 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
06392 if (ast_fileexists(prefile, NULL, NULL) > 0)
06393 ast_play_and_wait(chan, "vm-tempgreetactive");
06394 }
06395
06396
06397 if (!strncasecmp(chan->language, "de", 2)) {
06398 return vm_intro_de(chan, vms);
06399 } else if (!strncasecmp(chan->language, "es", 2)) {
06400 return vm_intro_es(chan, vms);
06401 } else if (!strncasecmp(chan->language, "it", 2)) {
06402 return vm_intro_it(chan, vms);
06403 } else if (!strncasecmp(chan->language, "fr", 2)) {
06404 return vm_intro_fr(chan, vms);
06405 } else if (!strncasecmp(chan->language, "nl", 2)) {
06406 return vm_intro_nl(chan, vms);
06407 } else if (!strcasecmp(chan->language, "pt_BR")) {
06408 return vm_intro_pt_BR(chan, vms);
06409 } else if (!strncasecmp(chan->language, "pt", 2)) {
06410 return vm_intro_pt(chan, vms);
06411 } else if (!strncasecmp(chan->language, "cz", 2)) {
06412 return vm_intro_cz(chan, vms);
06413 } else if (!strncasecmp(chan->language, "gr", 2)) {
06414 return vm_intro_gr(chan, vms);
06415 } else if (!strncasecmp(chan->language, "pl", 2)) {
06416 return vm_intro_pl(chan, vms);
06417 } else if (!strncasecmp(chan->language, "se", 2)) {
06418 return vm_intro_se(chan, vms);
06419 } else if (!strncasecmp(chan->language, "no", 2)) {
06420 return vm_intro_no(chan, vms);
06421 } else if (!strncasecmp(chan->language, "ru", 2)) {
06422 return vm_intro_ru(chan, vms);
06423 } else if (!strncasecmp(chan->language, "ua", 2)) {
06424 return vm_intro_ua(chan, vms);
06425 } else {
06426 return vm_intro_en(chan, vms);
06427 }
06428 }
06429
06430 static int vm_instructions(struct ast_channel *chan, struct vm_state *vms, int skipadvanced)
06431 {
06432 int res = 0;
06433
06434 while (!res) {
06435 if (vms->starting) {
06436 if (vms->lastmsg > -1) {
06437 res = ast_play_and_wait(chan, "vm-onefor");
06438 if (!res)
06439 res = vm_play_folder_name(chan, vms->vmbox);
06440 }
06441 if (!res)
06442 res = ast_play_and_wait(chan, "vm-opts");
06443 } else {
06444 if (vms->curmsg)
06445 res = ast_play_and_wait(chan, "vm-prev");
06446 if (!res && !skipadvanced)
06447 res = ast_play_and_wait(chan, "vm-advopts");
06448 if (!res)
06449 res = ast_play_and_wait(chan, "vm-repeat");
06450 if (!res && (vms->curmsg != vms->lastmsg))
06451 res = ast_play_and_wait(chan, "vm-next");
06452 if (!res) {
06453 if (!vms->deleted[vms->curmsg])
06454 res = ast_play_and_wait(chan, "vm-delete");
06455 else
06456 res = ast_play_and_wait(chan, "vm-undelete");
06457 if (!res)
06458 res = ast_play_and_wait(chan, "vm-toforward");
06459 if (!res)
06460 res = ast_play_and_wait(chan, "vm-savemessage");
06461 }
06462 }
06463 if (!res)
06464 res = ast_play_and_wait(chan, "vm-helpexit");
06465 if (!res)
06466 res = ast_waitfordigit(chan, 6000);
06467 if (!res) {
06468 vms->repeats++;
06469 if (vms->repeats > 2) {
06470 res = 't';
06471 }
06472 }
06473 }
06474 return res;
06475 }
06476
06477 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
06478 {
06479 int cmd = 0;
06480 int duration = 0;
06481 int tries = 0;
06482 char newpassword[80] = "";
06483 char newpassword2[80] = "";
06484 char prefile[PATH_MAX] = "";
06485 unsigned char buf[256];
06486 int bytes=0;
06487
06488 if (ast_adsi_available(chan)) {
06489 bytes += adsi_logo(buf + bytes);
06490 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
06491 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
06492 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06493 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06494 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06495 }
06496
06497
06498
06499 for (;;) {
06500 newpassword[1] = '\0';
06501 newpassword[0] = cmd = ast_play_and_wait(chan,"vm-newpassword");
06502 if (cmd == '#')
06503 newpassword[0] = '\0';
06504 if (cmd < 0 || cmd == 't' || cmd == '#')
06505 return cmd;
06506 cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#");
06507 if (cmd < 0 || cmd == 't' || cmd == '#')
06508 return cmd;
06509 newpassword2[1] = '\0';
06510 newpassword2[0] = cmd = ast_play_and_wait(chan,"vm-reenterpassword");
06511 if (cmd == '#')
06512 newpassword2[0] = '\0';
06513 if (cmd < 0 || cmd == 't' || cmd == '#')
06514 return cmd;
06515 cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#");
06516 if (cmd < 0 || cmd == 't' || cmd == '#')
06517 return cmd;
06518 if (!strcmp(newpassword, newpassword2))
06519 break;
06520 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
06521 cmd = ast_play_and_wait(chan, "vm-mismatch");
06522 if (++tries == 3)
06523 return -1;
06524 }
06525 if (ast_strlen_zero(ext_pass_cmd))
06526 vm_change_password(vmu,newpassword);
06527 else
06528 vm_change_password_shell(vmu,newpassword);
06529 if (option_debug > 2)
06530 ast_log(LOG_DEBUG,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
06531 cmd = ast_play_and_wait(chan,"vm-passchanged");
06532
06533
06534 if (ast_test_flag(vmu, VM_FORCENAME)) {
06535 snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
06536 if (ast_fileexists(prefile, NULL, NULL) < 1) {
06537 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06538 if (cmd < 0 || cmd == 't' || cmd == '#')
06539 return cmd;
06540 }
06541 }
06542
06543
06544 if (ast_test_flag(vmu, VM_FORCEGREET)) {
06545 snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
06546 if (ast_fileexists(prefile, NULL, NULL) < 1) {
06547 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06548 if (cmd < 0 || cmd == 't' || cmd == '#')
06549 return cmd;
06550 }
06551
06552 snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
06553 if (ast_fileexists(prefile, NULL, NULL) < 1) {
06554 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06555 if (cmd < 0 || cmd == 't' || cmd == '#')
06556 return cmd;
06557 }
06558 }
06559
06560 return cmd;
06561 }
06562
06563 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
06564 {
06565 int cmd = 0;
06566 int retries = 0;
06567 int duration = 0;
06568 char newpassword[80] = "";
06569 char newpassword2[80] = "";
06570 char prefile[PATH_MAX] = "";
06571 unsigned char buf[256];
06572 int bytes=0;
06573
06574 if (ast_adsi_available(chan))
06575 {
06576 bytes += adsi_logo(buf + bytes);
06577 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
06578 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
06579 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06580 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06581 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06582 }
06583 while ((cmd >= 0) && (cmd != 't')) {
06584 if (cmd)
06585 retries = 0;
06586 switch (cmd) {
06587 case '1':
06588 snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
06589 cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06590 break;
06591 case '2':
06592 snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
06593 cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06594 break;
06595 case '3':
06596 snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
06597 cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06598 break;
06599 case '4':
06600 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
06601 break;
06602 case '5':
06603 if (vmu->password[0] == '-') {
06604 cmd = ast_play_and_wait(chan, "vm-no");
06605 break;
06606 }
06607 newpassword[1] = '\0';
06608 newpassword[0] = cmd = ast_play_and_wait(chan,"vm-newpassword");
06609 if (cmd == '#')
06610 newpassword[0] = '\0';
06611 else {
06612 if (cmd < 0)
06613 break;
06614 if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0) {
06615 break;
06616 }
06617 }
06618 newpassword2[1] = '\0';
06619 newpassword2[0] = cmd = ast_play_and_wait(chan,"vm-reenterpassword");
06620 if (cmd == '#')
06621 newpassword2[0] = '\0';
06622 else {
06623 if (cmd < 0)
06624 break;
06625
06626 if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#"))) {
06627 break;
06628 }
06629 }
06630 if (strcmp(newpassword, newpassword2)) {
06631 ast_log(LOG_NOTICE,"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
06632 cmd = ast_play_and_wait(chan, "vm-mismatch");
06633 break;
06634 }
06635 if (ast_strlen_zero(ext_pass_cmd))
06636 vm_change_password(vmu,newpassword);
06637 else
06638 vm_change_password_shell(vmu,newpassword);
06639 if (option_debug > 2)
06640 ast_log(LOG_DEBUG,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
06641 cmd = ast_play_and_wait(chan,"vm-passchanged");
06642 break;
06643 case '*':
06644 cmd = 't';
06645 break;
06646 default:
06647 cmd = 0;
06648 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
06649 if (ast_fileexists(prefile, NULL, NULL))
06650 cmd = ast_play_and_wait(chan, "vm-tmpexists");
06651 if (!cmd)
06652 cmd = ast_play_and_wait(chan, "vm-options");
06653 if (!cmd)
06654 cmd = ast_waitfordigit(chan,6000);
06655 if (!cmd)
06656 retries++;
06657 if (retries > 3)
06658 cmd = 't';
06659 }
06660 }
06661 if (cmd == 't')
06662 cmd = 0;
06663 return cmd;
06664 }
06665
06666 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
06667 {
06668 int res;
06669 int cmd = 0;
06670 int retries = 0;
06671 int duration = 0;
06672 char prefile[PATH_MAX] = "";
06673 unsigned char buf[256];
06674 char dest[PATH_MAX];
06675 int bytes = 0;
06676
06677 if (ast_adsi_available(chan)) {
06678 bytes += adsi_logo(buf + bytes);
06679 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
06680 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
06681 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06682 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06683 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06684 }
06685
06686 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
06687 if ((res = create_dirpath(dest, sizeof(dest), vmu->context, vms->username, "temp"))) {
06688 ast_log(LOG_WARNING, "Failed to create directory (%s).\n", prefile);
06689 return -1;
06690 }
06691 while ((cmd >= 0) && (cmd != 't')) {
06692 if (cmd)
06693 retries = 0;
06694 RETRIEVE(prefile, -1, vmu);
06695 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
06696 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06697 cmd = 't';
06698 } else {
06699 switch (cmd) {
06700 case '1':
06701 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms);
06702 break;
06703 case '2':
06704 DELETE(prefile, -1, prefile, vmu);
06705 ast_play_and_wait(chan, "vm-tempremoved");
06706 cmd = 't';
06707 break;
06708 case '*':
06709 cmd = 't';
06710 break;
06711 default:
06712 cmd = ast_play_and_wait(chan,
06713 ast_fileexists(prefile, NULL, NULL) > 0 ?
06714 "vm-tempgreeting2" : "vm-tempgreeting");
06715 if (!cmd)
06716 cmd = ast_waitfordigit(chan,6000);
06717 if (!cmd)
06718 retries++;
06719 if (retries > 3)
06720 cmd = 't';
06721 }
06722 }
06723 DISPOSE(prefile, -1);
06724 }
06725 if (cmd == 't')
06726 cmd = 0;
06727 return cmd;
06728 }
06729
06730
06731 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
06732 {
06733 int cmd=0;
06734
06735 if (vms->lastmsg > -1) {
06736 cmd = play_message(chan, vmu, vms);
06737 } else {
06738 cmd = ast_play_and_wait(chan, "vm-youhave");
06739 if (!cmd)
06740 cmd = ast_play_and_wait(chan, "vm-no");
06741 if (!cmd) {
06742 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
06743 cmd = ast_play_and_wait(chan, vms->fn);
06744 }
06745 if (!cmd)
06746 cmd = ast_play_and_wait(chan, "vm-messages");
06747 }
06748 return cmd;
06749 }
06750
06751
06752 static int vm_browse_messages_latin(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
06753 {
06754 int cmd=0;
06755
06756 if (vms->lastmsg > -1) {
06757 cmd = play_message(chan, vmu, vms);
06758 } else {
06759 cmd = ast_play_and_wait(chan, "vm-youhaveno");
06760 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
06761 if (!cmd) {
06762 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
06763 cmd = ast_play_and_wait(chan, vms->fn);
06764 }
06765 if (!cmd)
06766 cmd = ast_play_and_wait(chan, "vm-messages");
06767 } else {
06768 if (!cmd)
06769 cmd = ast_play_and_wait(chan, "vm-messages");
06770 if (!cmd) {
06771 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
06772 cmd = ast_play_and_wait(chan, vms->fn);
06773 }
06774 }
06775 }
06776 return cmd;
06777 }
06778
06779 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
06780 {
06781 if (!strncasecmp(chan->language, "es", 2) ||
06782 !strncasecmp(chan->language, "it", 2) ||
06783 !strncasecmp(chan->language, "pt", 2) ||
06784 !strncasecmp(chan->language, "gr", 2)) {
06785 return vm_browse_messages_latin(chan, vms, vmu);
06786 } else {
06787 return vm_browse_messages_en(chan, vms, vmu);
06788 }
06789 }
06790
06791 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
06792 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
06793 int skipuser, int maxlogins, int silent)
06794 {
06795 int useadsi=0, valid=0, logretries=0;
06796 char password[AST_MAX_EXTENSION]="", *passptr;
06797 struct ast_vm_user vmus, *vmu = NULL;
06798
06799
06800 adsi_begin(chan, &useadsi);
06801 if (!skipuser && useadsi)
06802 adsi_login(chan);
06803 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
06804 ast_log(LOG_WARNING, "Couldn't stream login file\n");
06805 return -1;
06806 }
06807
06808
06809
06810 while (!valid && (logretries < maxlogins)) {
06811
06812 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
06813 ast_log(LOG_WARNING, "Couldn't read username\n");
06814 return -1;
06815 }
06816 if (ast_strlen_zero(mailbox)) {
06817 if (chan->cid.cid_num) {
06818 ast_copy_string(mailbox, chan->cid.cid_num, mailbox_size);
06819 } else {
06820 if (option_verbose > 2)
06821 ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
06822 return -1;
06823 }
06824 }
06825 if (useadsi)
06826 adsi_password(chan);
06827
06828 if (!ast_strlen_zero(prefix)) {
06829 char fullusername[80] = "";
06830 ast_copy_string(fullusername, prefix, sizeof(fullusername));
06831 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
06832 ast_copy_string(mailbox, fullusername, mailbox_size);
06833 }
06834
06835 if (option_debug)
06836 ast_log(LOG_DEBUG, "Before find user for mailbox %s\n",mailbox);
06837 vmu = find_user(&vmus, context, mailbox);
06838 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
06839
06840 password[0] = '\0';
06841 } else {
06842 if (ast_streamfile(chan, "vm-password", chan->language)) {
06843 ast_log(LOG_WARNING, "Unable to stream password file\n");
06844 return -1;
06845 }
06846 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
06847 ast_log(LOG_WARNING, "Unable to read password\n");
06848 return -1;
06849 }
06850 }
06851
06852 if (vmu) {
06853 passptr = vmu->password;
06854 if (passptr[0] == '-') passptr++;
06855 }
06856 if (vmu && !strcmp(passptr, password))
06857 valid++;
06858 else {
06859 if (option_verbose > 2)
06860 ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
06861 if (!ast_strlen_zero(prefix))
06862 mailbox[0] = '\0';
06863 }
06864 logretries++;
06865 if (!valid) {
06866 if (skipuser || logretries >= maxlogins) {
06867 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
06868 ast_log(LOG_WARNING, "Unable to stream incorrect message\n");
06869 return -1;
06870 }
06871 } else {
06872 if (useadsi)
06873 adsi_login(chan);
06874 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
06875 ast_log(LOG_WARNING, "Unable to stream incorrect mailbox message\n");
06876 return -1;
06877 }
06878 }
06879 if (ast_waitstream(chan, ""))
06880 return -1;
06881 }
06882 }
06883 if (!valid && (logretries >= maxlogins)) {
06884 ast_stopstream(chan);
06885 ast_play_and_wait(chan, "vm-goodbye");
06886 return -1;
06887 }
06888 if (vmu && !skipuser) {
06889 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
06890 }
06891 return 0;
06892 }
06893
06894 static int vm_execmain(struct ast_channel *chan, void *data)
06895 {
06896
06897
06898
06899 int res=-1;
06900 int cmd=0;
06901 int valid = 0;
06902 struct ast_module_user *u;
06903 char prefixstr[80] ="";
06904 char ext_context[256]="";
06905 int box;
06906 int useadsi = 0;
06907 int skipuser = 0;
06908 struct vm_state vms;
06909 struct ast_vm_user *vmu = NULL, vmus;
06910 char *context=NULL;
06911 int silentexit = 0;
06912 struct ast_flags flags = { 0 };
06913 signed char record_gain = 0;
06914 int play_auto = 0;
06915 int play_folder = 0;
06916 #ifdef IMAP_STORAGE
06917 int deleted = 0;
06918 #endif
06919 u = ast_module_user_add(chan);
06920
06921
06922 memset(&vms, 0, sizeof(vms));
06923 vms.lastmsg = -1;
06924
06925 memset(&vmus, 0, sizeof(vmus));
06926
06927 if (chan->_state != AST_STATE_UP) {
06928 if (option_debug)
06929 ast_log(LOG_DEBUG, "Before ast_answer\n");
06930 ast_answer(chan);
06931 }
06932
06933 if (!ast_strlen_zero(data)) {
06934 char *opts[OPT_ARG_ARRAY_SIZE];
06935 char *parse;
06936 AST_DECLARE_APP_ARGS(args,
06937 AST_APP_ARG(argv0);
06938 AST_APP_ARG(argv1);
06939 );
06940
06941 parse = ast_strdupa(data);
06942
06943 AST_STANDARD_APP_ARGS(args, parse);
06944
06945 if (args.argc == 2) {
06946 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1)) {
06947 ast_module_user_remove(u);
06948 return -1;
06949 }
06950 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
06951 int gain;
06952 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
06953 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%d", &gain) != 1) {
06954 ast_log(LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
06955 ast_module_user_remove(u);
06956 return -1;
06957 } else {
06958 record_gain = (signed char) gain;
06959 }
06960 } else {
06961 ast_log(LOG_WARNING, "Invalid Gain level set with option g\n");
06962 }
06963 }
06964 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
06965 play_auto = 1;
06966 if (opts[OPT_ARG_PLAYFOLDER]) {
06967 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%d", &play_folder) != 1) {
06968 ast_log(LOG_WARNING, "Invalid value '%s' provided for folder autoplay option\n", opts[OPT_ARG_PLAYFOLDER]);
06969 }
06970 } else {
06971 ast_log(LOG_WARNING, "Invalid folder set with option a\n");
06972 }
06973 if ( play_folder > 9 || play_folder < 0) {
06974 ast_log(LOG_WARNING, "Invalid value '%d' provided for folder autoplay option\n", play_folder);
06975 play_folder = 0;
06976 }
06977 }
06978 } else {
06979
06980 while (*(args.argv0)) {
06981 if (*(args.argv0) == 's')
06982 ast_set_flag(&flags, OPT_SILENT);
06983 else if (*(args.argv0) == 'p')
06984 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
06985 else
06986 break;
06987 (args.argv0)++;
06988 }
06989
06990 }
06991
06992 valid = ast_test_flag(&flags, OPT_SILENT);
06993
06994 if ((context = strchr(args.argv0, '@')))
06995 *context++ = '\0';
06996
06997 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
06998 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
06999 else
07000 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
07001
07002 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
07003 skipuser++;
07004 else
07005 valid = 0;
07006 }
07007
07008 if (!valid)
07009 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
07010
07011 if (option_debug)
07012 ast_log(LOG_DEBUG, "After vm_authenticate\n");
07013 if (!res) {
07014 valid = 1;
07015 if (!skipuser)
07016 vmu = &vmus;
07017 } else {
07018 res = 0;
07019 }
07020
07021
07022 adsi_begin(chan, &useadsi);
07023
07024 #ifdef IMAP_STORAGE
07025 vms.interactive = 1;
07026 vms.updated = 1;
07027 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
07028 vmstate_insert(&vms);
07029 init_vm_state(&vms);
07030 #endif
07031 if (!valid)
07032 goto out;
07033
07034 if (!(vms.deleted = ast_calloc(vmu->maxmsg, sizeof(int)))) {
07035
07036 }
07037 if (!(vms.heard = ast_calloc(vmu->maxmsg, sizeof(int)))) {
07038
07039 }
07040
07041
07042 if (!ast_strlen_zero(vmu->language))
07043 ast_string_field_set(chan, language, vmu->language);
07044 create_dirpath(vms.curdir, sizeof(vms.curdir), vmu->context, vms.username, "");
07045
07046 if (option_debug)
07047 ast_log(LOG_DEBUG, "Before open_mailbox\n");
07048 res = open_mailbox(&vms, vmu, 1);
07049 if (res == ERROR_LOCK_PATH)
07050 goto out;
07051 vms.oldmessages = vms.lastmsg + 1;
07052 if (option_debug > 2)
07053 ast_log(LOG_DEBUG, "Number of old messages: %d\n",vms.oldmessages);
07054
07055 res = open_mailbox(&vms, vmu, 0);
07056 if (res == ERROR_LOCK_PATH)
07057 goto out;
07058 vms.newmessages = vms.lastmsg + 1;
07059 if (option_debug > 2)
07060 ast_log(LOG_DEBUG, "Number of new messages: %d\n",vms.newmessages);
07061
07062
07063 if (play_auto) {
07064 res = open_mailbox(&vms, vmu, play_folder);
07065 if (res == ERROR_LOCK_PATH)
07066 goto out;
07067
07068
07069 if (vms.lastmsg == -1) {
07070 cmd = vm_browse_messages(chan, &vms, vmu);
07071 res = 0;
07072 goto out;
07073 }
07074 } else {
07075 if (!vms.newmessages && vms.oldmessages) {
07076
07077 res = open_mailbox(&vms, vmu, 1);
07078 play_folder = 1;
07079 if (res == ERROR_LOCK_PATH)
07080 goto out;
07081 }
07082 }
07083
07084 if (useadsi)
07085 adsi_status(chan, &vms);
07086 res = 0;
07087
07088
07089 if (!strcasecmp(vmu->mailbox, vmu->password) &&
07090 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
07091 if (ast_play_and_wait(chan, "vm-newuser") == -1)
07092 ast_log(LOG_WARNING, "Couldn't stream new user file\n");
07093 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
07094 if ((cmd == 't') || (cmd == '#')) {
07095
07096 res = 0;
07097 goto out;
07098 } else if (cmd < 0) {
07099
07100 res = -1;
07101 goto out;
07102 }
07103 }
07104 #ifdef IMAP_STORAGE
07105 if (option_debug > 2)
07106 ast_log(LOG_DEBUG, "Checking quotas: comparing %u to %u\n",vms.quota_usage,vms.quota_limit);
07107 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
07108 if (option_debug)
07109 ast_log(LOG_DEBUG, "*** QUOTA EXCEEDED!!\n");
07110 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
07111 }
07112 if (option_debug > 2)
07113 ast_log(LOG_DEBUG, "Checking quotas: User has %d messages and limit is %d.\n",(vms.newmessages + vms.oldmessages),vmu->maxmsg);
07114 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
07115 ast_log(LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n",(vms.newmessages + vms.oldmessages),vmu->maxmsg);
07116 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
07117 }
07118 #endif
07119 if (play_auto) {
07120 cmd = '1';
07121 } else {
07122 cmd = vm_intro(chan, vmu, &vms);
07123 }
07124
07125 vms.repeats = 0;
07126 vms.starting = 1;
07127 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
07128
07129 switch (cmd) {
07130 case '1':
07131 vms.curmsg = 0;
07132
07133 case '5':
07134 cmd = vm_browse_messages(chan, &vms, vmu);
07135 break;
07136 case '2':
07137 if (useadsi)
07138 adsi_folders(chan, 0, "Change to folder...");
07139 cmd = get_folder2(chan, "vm-changeto", 0);
07140 if (cmd == '#') {
07141 cmd = 0;
07142 } else if (cmd > 0) {
07143 cmd = cmd - '0';
07144 res = close_mailbox(&vms, vmu);
07145 if (res == ERROR_LOCK_PATH)
07146 goto out;
07147 res = open_mailbox(&vms, vmu, cmd);
07148 if (res == ERROR_LOCK_PATH)
07149 goto out;
07150 play_folder = cmd;
07151 cmd = 0;
07152 }
07153 if (useadsi)
07154 adsi_status2(chan, &vms);
07155
07156 if (!cmd)
07157 cmd = vm_play_folder_name(chan, vms.vmbox);
07158
07159 vms.starting = 1;
07160 break;
07161 case '3':
07162 cmd = 0;
07163 vms.repeats = 0;
07164 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
07165 switch (cmd) {
07166 case '1':
07167 if (vms.lastmsg > -1 && !vms.starting) {
07168 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
07169 if (cmd == ERROR_LOCK_PATH) {
07170 res = cmd;
07171 goto out;
07172 }
07173 } else
07174 cmd = ast_play_and_wait(chan, "vm-sorry");
07175 cmd = 't';
07176 break;
07177 case '2':
07178 if (option_verbose > 2 && !vms.starting)
07179 ast_verbose( VERBOSE_PREFIX_3 "Callback Requested\n");
07180 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
07181 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
07182 if (cmd == 9) {
07183 silentexit = 1;
07184 goto out;
07185 } else if (cmd == ERROR_LOCK_PATH) {
07186 res = cmd;
07187 goto out;
07188 }
07189 }
07190 else
07191 cmd = ast_play_and_wait(chan, "vm-sorry");
07192 cmd = 't';
07193 break;
07194 case '3':
07195 if (vms.lastmsg > -1 && !vms.starting) {
07196 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
07197 if (cmd == ERROR_LOCK_PATH) {
07198 res = cmd;
07199 goto out;
07200 }
07201 } else
07202 cmd = ast_play_and_wait(chan, "vm-sorry");
07203 cmd = 't';
07204 break;
07205 case '4':
07206 if (!ast_strlen_zero(vmu->dialout)) {
07207 cmd = dialout(chan, vmu, NULL, vmu->dialout);
07208 if (cmd == 9) {
07209 silentexit = 1;
07210 goto out;
07211 }
07212 }
07213 else
07214 cmd = ast_play_and_wait(chan, "vm-sorry");
07215 cmd = 't';
07216 break;
07217
07218 case '5':
07219 if (ast_test_flag(vmu, VM_SVMAIL)) {
07220 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain);
07221 if (cmd == ERROR_LOCK_PATH) {
07222 res = cmd;
07223 ast_log(LOG_WARNING, "forward_message failed to lock path.\n");
07224 goto out;
07225 }
07226 } else
07227 cmd = ast_play_and_wait(chan,"vm-sorry");
07228 cmd='t';
07229 break;
07230
07231 case '*':
07232 cmd = 't';
07233 break;
07234
07235 default:
07236 cmd = 0;
07237 if (!vms.starting) {
07238 cmd = ast_play_and_wait(chan, "vm-toreply");
07239 }
07240 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
07241 cmd = ast_play_and_wait(chan, "vm-tocallback");
07242 }
07243 if (!cmd && !vms.starting) {
07244 cmd = ast_play_and_wait(chan, "vm-tohearenv");
07245 }
07246 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
07247 cmd = ast_play_and_wait(chan, "vm-tomakecall");
07248 }
07249 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd)
07250 cmd=ast_play_and_wait(chan, "vm-leavemsg");
07251 if (!cmd)
07252 cmd = ast_play_and_wait(chan, "vm-starmain");
07253 if (!cmd)
07254 cmd = ast_waitfordigit(chan,6000);
07255 if (!cmd)
07256 vms.repeats++;
07257 if (vms.repeats > 3)
07258 cmd = 't';
07259 }
07260 }
07261 if (cmd == 't') {
07262 cmd = 0;
07263 vms.repeats = 0;
07264 }
07265 break;
07266 case '4':
07267 if (vms.curmsg > 0) {
07268 vms.curmsg--;
07269 cmd = play_message(chan, vmu, &vms);
07270 } else {
07271 cmd = ast_play_and_wait(chan, "vm-nomore");
07272 }
07273 break;
07274 case '6':
07275 if (vms.curmsg < vms.lastmsg) {
07276 vms.curmsg++;
07277 cmd = play_message(chan, vmu, &vms);
07278 } else {
07279 cmd = ast_play_and_wait(chan, "vm-nomore");
07280 }
07281 break;
07282 case '7':
07283 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
07284 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
07285 if (useadsi)
07286 adsi_delete(chan, &vms);
07287 if (vms.deleted[vms.curmsg]) {
07288 if (play_folder == 0)
07289 vms.newmessages--;
07290 else if (play_folder == 1)
07291 vms.oldmessages--;
07292 cmd = ast_play_and_wait(chan, "vm-deleted");
07293 }
07294 else {
07295 if (play_folder == 0)
07296 vms.newmessages++;
07297 else if (play_folder == 1)
07298 vms.oldmessages++;
07299 cmd = ast_play_and_wait(chan, "vm-undeleted");
07300 }
07301 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
07302 if (vms.curmsg < vms.lastmsg) {
07303 vms.curmsg++;
07304 cmd = play_message(chan, vmu, &vms);
07305 } else {
07306 cmd = ast_play_and_wait(chan, "vm-nomore");
07307 }
07308 }
07309 } else
07310 cmd = 0;
07311 #ifdef IMAP_STORAGE
07312 deleted = 1;
07313 #endif
07314 break;
07315
07316 case '8':
07317 if (vms.lastmsg > -1) {
07318 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain);
07319 if (cmd == ERROR_LOCK_PATH) {
07320 res = cmd;
07321 goto out;
07322 }
07323 } else
07324 cmd = ast_play_and_wait(chan, "vm-nomore");
07325 break;
07326 case '9':
07327 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
07328
07329 cmd = 0;
07330 break;
07331 }
07332 if (useadsi)
07333 adsi_folders(chan, 1, "Save to folder...");
07334 cmd = get_folder2(chan, "vm-savefolder", 1);
07335 box = 0;
07336 if (cmd == '#') {
07337 cmd = 0;
07338 break;
07339 } else if (cmd > 0) {
07340 box = cmd = cmd - '0';
07341 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
07342 if (cmd == ERROR_LOCK_PATH) {
07343 res = cmd;
07344 goto out;
07345 #ifndef IMAP_STORAGE
07346 } else if (!cmd) {
07347 vms.deleted[vms.curmsg] = 1;
07348 #endif
07349 } else {
07350 vms.deleted[vms.curmsg] = 0;
07351 vms.heard[vms.curmsg] = 0;
07352 }
07353 }
07354 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
07355 if (useadsi)
07356 adsi_message(chan, &vms);
07357 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
07358 if (!cmd) {
07359 cmd = ast_play_and_wait(chan, "vm-message");
07360 if (!cmd)
07361 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
07362 if (!cmd)
07363 cmd = ast_play_and_wait(chan, "vm-savedto");
07364 if (!cmd)
07365 cmd = vm_play_folder_name(chan, vms.fn);
07366 } else {
07367 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
07368 }
07369 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
07370 if (vms.curmsg < vms.lastmsg) {
07371 vms.curmsg++;
07372 cmd = play_message(chan, vmu, &vms);
07373 } else {
07374 cmd = ast_play_and_wait(chan, "vm-nomore");
07375 }
07376 }
07377 break;
07378 case '*':
07379 if (!vms.starting) {
07380 cmd = ast_play_and_wait(chan, "vm-onefor");
07381 if (!cmd)
07382 cmd = vm_play_folder_name(chan, vms.vmbox);
07383 if (!cmd)
07384 cmd = ast_play_and_wait(chan, "vm-opts");
07385 if (!cmd)
07386 cmd = vm_instructions(chan, &vms, 1);
07387 } else
07388 cmd = 0;
07389 break;
07390 case '0':
07391 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
07392 if (useadsi)
07393 adsi_status(chan, &vms);
07394 break;
07395 default:
07396 cmd = vm_instructions(chan, &vms, 0);
07397 break;
07398 }
07399 }
07400 if ((cmd == 't') || (cmd == '#')) {
07401
07402 res = 0;
07403 } else {
07404
07405 res = -1;
07406 }
07407
07408 out:
07409 if (res > -1) {
07410 ast_stopstream(chan);
07411 adsi_goodbye(chan);
07412 if (valid) {
07413 if (silentexit)
07414 res = ast_play_and_wait(chan, "vm-dialout");
07415 else
07416 res = ast_play_and_wait(chan, "vm-goodbye");
07417 if (res > 0)
07418 res = 0;
07419 }
07420 if (useadsi)
07421 ast_adsi_unload_session(chan);
07422 }
07423 if (vmu)
07424 close_mailbox(&vms, vmu);
07425 if (valid) {
07426 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
07427 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
07428 run_externnotify(vmu->context, vmu->mailbox);
07429 }
07430 #ifdef IMAP_STORAGE
07431
07432 if (option_debug > 2)
07433 ast_log(LOG_DEBUG, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n",deleted,expungeonhangup);
07434 if (vmu && deleted == 1 && expungeonhangup == 1) {
07435 #ifdef HAVE_IMAP_TK2006
07436 if (LEVELUIDPLUS (vms.mailstream)) {
07437 mail_expunge_full(vms.mailstream,NIL,EX_UID);
07438 } else
07439 #endif
07440 mail_expunge(vms.mailstream);
07441 }
07442
07443
07444 vmstate_delete(&vms);
07445 #endif
07446 if (vmu)
07447 free_user(vmu);
07448 if (vms.deleted)
07449 free(vms.deleted);
07450 if (vms.heard)
07451 free(vms.heard);
07452 ast_module_user_remove(u);
07453
07454 return res;
07455 }
07456
07457 static int vm_exec(struct ast_channel *chan, void *data)
07458 {
07459 int res = 0;
07460 struct ast_module_user *u;
07461 char *tmp;
07462 struct leave_vm_options leave_options;
07463 struct ast_flags flags = { 0 };
07464 static int deprecate_warning = 0;
07465 char *opts[OPT_ARG_ARRAY_SIZE];
07466 AST_DECLARE_APP_ARGS(args,
07467 AST_APP_ARG(argv0);
07468 AST_APP_ARG(argv1);
07469 );
07470
07471 u = ast_module_user_add(chan);
07472
07473 memset(&leave_options, 0, sizeof(leave_options));
07474
07475 if (chan->_state != AST_STATE_UP)
07476 ast_answer(chan);
07477
07478 if (!ast_strlen_zero(data)) {
07479 tmp = ast_strdupa(data);
07480 AST_STANDARD_APP_ARGS(args, tmp);
07481 if (args.argc == 2) {
07482 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1)) {
07483 ast_module_user_remove(u);
07484 return -1;
07485 }
07486 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_PRIORITY_JUMP);
07487 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
07488 int gain;
07489
07490 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%d", &gain) != 1) {
07491 ast_log(LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
07492 ast_module_user_remove(u);
07493 return -1;
07494 } else {
07495 leave_options.record_gain = (signed char) gain;
07496 }
07497 }
07498 } else {
07499
07500 int old = 0;
07501 char *orig_argv0 = args.argv0;
07502 while (*(args.argv0)) {
07503 if (*(args.argv0) == 's') {
07504 old = 1;
07505 ast_set_flag(&leave_options, OPT_SILENT);
07506 } else if (*(args.argv0) == 'b') {
07507 old = 1;
07508 ast_set_flag(&leave_options, OPT_BUSY_GREETING);
07509 } else if (*(args.argv0) == 'u') {
07510 old = 1;
07511 ast_set_flag(&leave_options, OPT_UNAVAIL_GREETING);
07512 } else if (*(args.argv0) == 'j') {
07513 old = 1;
07514 ast_set_flag(&leave_options, OPT_PRIORITY_JUMP);
07515 } else
07516 break;
07517 (args.argv0)++;
07518 }
07519 if (!deprecate_warning && old) {
07520 deprecate_warning = 1;
07521 ast_log(LOG_WARNING, "Prefixing the mailbox with an option is deprecated ('%s').\n", orig_argv0);
07522 ast_log(LOG_WARNING, "Please move all leading options to the second argument.\n");
07523 }
07524 }
07525 } else {
07526 char tmp[256];
07527 res = ast_app_getdata(chan, "vm-whichbox", tmp, sizeof(tmp) - 1, 0);
07528 if (res < 0) {
07529 ast_module_user_remove(u);
07530 return res;
07531 }
07532 if (ast_strlen_zero(tmp)) {
07533 ast_module_user_remove(u);
07534 return 0;
07535 }
07536 args.argv0 = ast_strdupa(tmp);
07537 }
07538
07539 res = leave_voicemail(chan, args.argv0, &leave_options);
07540
07541 if (res == ERROR_LOCK_PATH) {
07542 ast_log(LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
07543
07544 if (ast_test_flag(&leave_options, OPT_PRIORITY_JUMP) || ast_opt_priority_jumping)
07545 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
07546 ast_log(LOG_WARNING, "Extension %s, priority %d doesn't exist.\n", chan->exten, chan->priority + 101);
07547 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
07548 res = 0;
07549 }
07550
07551 ast_module_user_remove(u);
07552
07553 return res;
07554 }
07555
07556 static struct ast_vm_user *find_or_create(char *context, char *mbox)
07557 {
07558 struct ast_vm_user *vmu;
07559 AST_LIST_TRAVERSE(&users, vmu, list) {
07560 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mbox, vmu->mailbox))
07561 break;
07562 if (context && (!strcasecmp(context, vmu->context)) && (!strcasecmp(mbox, vmu->mailbox)))
07563 break;
07564 }
07565
07566 if (!vmu) {
07567 if ((vmu = ast_calloc(1, sizeof(*vmu)))) {
07568 ast_copy_string(vmu->context, context, sizeof(vmu->context));
07569 ast_copy_string(vmu->mailbox, mbox, sizeof(vmu->mailbox));
07570 AST_LIST_INSERT_TAIL(&users, vmu, list);
07571 }
07572 }
07573 return vmu;
07574 }
07575
07576 static int append_mailbox(char *context, char *mbox, char *data)
07577 {
07578
07579 char *tmp;
07580 char *stringp;
07581 char *s;
07582 struct ast_vm_user *vmu;
07583
07584 tmp = ast_strdupa(data);
07585
07586 if ((vmu = find_or_create(context, mbox))) {
07587 populate_defaults(vmu);
07588
07589 stringp = tmp;
07590 if ((s = strsep(&stringp, ",")))
07591 ast_copy_string(vmu->password, s, sizeof(vmu->password));
07592 if (stringp && (s = strsep(&stringp, ",")))
07593 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
07594 if (stringp && (s = strsep(&stringp, ",")))
07595 ast_copy_string(vmu->email, s, sizeof(vmu->email));
07596 if (stringp && (s = strsep(&stringp, ",")))
07597 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
07598 if (stringp && (s = strsep(&stringp, ",")))
07599 apply_options(vmu, s);
07600 }
07601 return 0;
07602 }
07603
07604 static int vm_box_exists(struct ast_channel *chan, void *data)
07605 {
07606 struct ast_module_user *u;
07607 struct ast_vm_user svm;
07608 char *context, *box;
07609 int priority_jump = 0;
07610 AST_DECLARE_APP_ARGS(args,
07611 AST_APP_ARG(mbox);
07612 AST_APP_ARG(options);
07613 );
07614
07615 if (ast_strlen_zero(data)) {
07616 ast_log(LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
07617 return -1;
07618 }
07619
07620 u = ast_module_user_add(chan);
07621
07622 box = ast_strdupa(data);
07623
07624 AST_STANDARD_APP_ARGS(args, box);
07625
07626 if (args.options) {
07627 if (strchr(args.options, 'j'))
07628 priority_jump = 1;
07629 }
07630
07631 if ((context = strchr(args.mbox, '@'))) {
07632 *context = '\0';
07633 context++;
07634 }
07635
07636 if (find_user(&svm, context, args.mbox)) {
07637 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
07638 if (priority_jump || ast_opt_priority_jumping)
07639 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
07640 ast_log(LOG_WARNING, "VM box %s@%s exists, but extension %s, priority %d doesn't exist\n", box, context, chan->exten, chan->priority + 101);
07641 } else
07642 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
07643 ast_module_user_remove(u);
07644 return 0;
07645 }
07646
07647 static int vmauthenticate(struct ast_channel *chan, void *data)
07648 {
07649 struct ast_module_user *u;
07650 char *s = data, *user=NULL, *context=NULL, mailbox[AST_MAX_EXTENSION] = "";
07651 struct ast_vm_user vmus;
07652 char *options = NULL;
07653 int silent = 0, skipuser = 0;
07654 int res = -1;
07655
07656 u = ast_module_user_add(chan);
07657
07658 if (s) {
07659 s = ast_strdupa(s);
07660 user = strsep(&s, "|");
07661 options = strsep(&s, "|");
07662 if (user) {
07663 s = user;
07664 user = strsep(&s, "@");
07665 context = strsep(&s, "");
07666 if (!ast_strlen_zero(user))
07667 skipuser++;
07668 ast_copy_string(mailbox, user, sizeof(mailbox));
07669 }
07670 }
07671
07672 if (options) {
07673 silent = (strchr(options, 's')) != NULL;
07674 }
07675
07676 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
07677 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
07678 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
07679 ast_play_and_wait(chan, "auth-thankyou");
07680 res = 0;
07681 }
07682
07683 ast_module_user_remove(u);
07684 return res;
07685 }
07686
07687 static char voicemail_show_users_help[] =
07688 "Usage: voicemail show users [for <context>]\n"
07689 " Lists all mailboxes currently set up\n";
07690
07691 static char voicemail_show_zones_help[] =
07692 "Usage: voicemail show zones\n"
07693 " Lists zone message formats\n";
07694
07695 static int handle_voicemail_show_users(int fd, int argc, char *argv[])
07696 {
07697 struct ast_vm_user *vmu;
07698 char *output_format = "%-10s %-5s %-25s %-10s %6s\n";
07699
07700 if ((argc < 3) || (argc > 5) || (argc == 4)) return RESULT_SHOWUSAGE;
07701 else if ((argc == 5) && strcmp(argv[3],"for")) return RESULT_SHOWUSAGE;
07702
07703 AST_LIST_LOCK(&users);
07704 if (!AST_LIST_EMPTY(&users)) {
07705 if (argc == 3)
07706 ast_cli(fd, output_format, "Context", "Mbox", "User", "Zone", "NewMsg");
07707 else {
07708 int count = 0;
07709 AST_LIST_TRAVERSE(&users, vmu, list) {
07710 if (!strcmp(argv[4],vmu->context))
07711 count++;
07712 }
07713 if (count) {
07714 ast_cli(fd, output_format, "Context", "Mbox", "User", "Zone", "NewMsg");
07715 } else {
07716 ast_cli(fd, "No such voicemail context \"%s\"\n", argv[4]);
07717 AST_LIST_UNLOCK(&users);
07718 return RESULT_FAILURE;
07719 }
07720 }
07721 AST_LIST_TRAVERSE(&users, vmu, list) {
07722 int newmsgs = 0, oldmsgs = 0;
07723 char count[12], tmp[256] = "";
07724
07725 if ((argc == 3) || ((argc == 5) && !strcmp(argv[4],vmu->context))) {
07726 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
07727 inboxcount(tmp, &newmsgs, &oldmsgs);
07728 snprintf(count,sizeof(count),"%d",newmsgs);
07729 ast_cli(fd, output_format, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
07730 }
07731 }
07732 } else {
07733 ast_cli(fd, "There are no voicemail users currently defined\n");
07734 AST_LIST_UNLOCK(&users);
07735 return RESULT_FAILURE;
07736 }
07737 AST_LIST_UNLOCK(&users);
07738 return RESULT_SUCCESS;
07739 }
07740
07741 static int handle_voicemail_show_zones(int fd, int argc, char *argv[])
07742 {
07743 struct vm_zone *zone;
07744 char *output_format = "%-15s %-20s %-45s\n";
07745 int res = RESULT_SUCCESS;
07746
07747 if (argc != 3)
07748 return RESULT_SHOWUSAGE;
07749
07750 AST_LIST_LOCK(&zones);
07751 if (!AST_LIST_EMPTY(&zones)) {
07752 ast_cli(fd, output_format, "Zone", "Timezone", "Message Format");
07753 AST_LIST_TRAVERSE(&zones, zone, list) {
07754 ast_cli(fd, output_format, zone->name, zone->timezone, zone->msg_format);
07755 }
07756 } else {
07757 ast_cli(fd, "There are no voicemail zones currently defined\n");
07758 res = RESULT_FAILURE;
07759 }
07760 AST_LIST_UNLOCK(&zones);
07761
07762 return res;
07763 }
07764
07765 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
07766 {
07767 int which = 0;
07768 int wordlen;
07769 struct ast_vm_user *vmu;
07770 const char *context = "";
07771
07772
07773 if (pos > 4)
07774 return NULL;
07775 if (pos == 3)
07776 return (state == 0) ? ast_strdup("for") : NULL;
07777 wordlen = strlen(word);
07778 AST_LIST_TRAVERSE(&users, vmu, list) {
07779 if (!strncasecmp(word, vmu->context, wordlen)) {
07780 if (context && strcmp(context, vmu->context) && ++which > state)
07781 return ast_strdup(vmu->context);
07782
07783 context = vmu->context;
07784 }
07785 }
07786 return NULL;
07787 }
07788
07789 static struct ast_cli_entry cli_show_voicemail_users_deprecated = {
07790 { "show", "voicemail", "users", NULL },
07791 handle_voicemail_show_users, NULL,
07792 NULL, complete_voicemail_show_users };
07793
07794 static struct ast_cli_entry cli_show_voicemail_zones_deprecated = {
07795 { "show", "voicemail", "zones", NULL },
07796 handle_voicemail_show_zones, NULL,
07797 NULL, NULL };
07798
07799 static struct ast_cli_entry cli_voicemail[] = {
07800 { { "voicemail", "show", "users", NULL },
07801 handle_voicemail_show_users, "List defined voicemail boxes",
07802 voicemail_show_users_help, complete_voicemail_show_users, &cli_show_voicemail_users_deprecated },
07803
07804 { { "voicemail", "show", "zones", NULL },
07805 handle_voicemail_show_zones, "List zone message formats",
07806 voicemail_show_zones_help, NULL, &cli_show_voicemail_zones_deprecated },
07807 };
07808
07809 static void free_vm_users(void)
07810 {
07811 struct ast_vm_user *cur;
07812 struct vm_zone *zcur;
07813
07814 AST_LIST_LOCK(&users);
07815 while ((cur = AST_LIST_REMOVE_HEAD(&users, list))) {
07816 ast_set_flag(cur, VM_ALLOCED);
07817 free_user(cur);
07818 }
07819 AST_LIST_UNLOCK(&users);
07820
07821 AST_LIST_LOCK(&zones);
07822 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list))) {
07823 free_zone(zcur);
07824 }
07825 AST_LIST_UNLOCK(&zones);
07826 }
07827
07828 static int load_config(void)
07829 {
07830 struct ast_vm_user *cur;
07831 struct ast_config *cfg, *ucfg;
07832 char *cat;
07833 struct ast_variable *var;
07834 const char *notifystr = NULL;
07835 const char *smdistr = NULL;
07836 const char *astattach;
07837 const char *astsearch;
07838 const char *astsaycid;
07839 const char *send_voicemail;
07840 #ifdef IMAP_STORAGE
07841 const char *imap_server;
07842 const char *imap_port;
07843 const char *imap_flags;
07844 const char *imap_folder;
07845 const char *auth_user;
07846 const char *auth_password;
07847 const char *expunge_on_hangup;
07848 const char *imap_timeout;
07849 #endif
07850 const char *astcallop;
07851 const char *astreview;
07852 const char *asttempgreetwarn;
07853 const char *astskipcmd;
07854 const char *asthearenv;
07855 const char *astsaydurationinfo;
07856 const char *astsaydurationminfo;
07857 const char *silencestr;
07858 const char *maxmsgstr;
07859 const char *astdirfwd;
07860 const char *thresholdstr;
07861 const char *fmt;
07862 const char *astemail;
07863 const char *ucontext;
07864 const char *astmailcmd = SENDMAIL;
07865 const char *astforcename;
07866 const char *astforcegreet;
07867 const char *s;
07868 char *q,*stringp;
07869 const char *dialoutcxt = NULL;
07870 const char *callbackcxt = NULL;
07871 const char *exitcxt = NULL;
07872 const char *extpc;
07873 const char *emaildateformatstr;
07874 const char *volgainstr;
07875 int x;
07876 int tmpadsi[4];
07877
07878 cfg = ast_config_load(VOICEMAIL_CONFIG);
07879
07880 free_vm_users();
07881
07882 AST_LIST_LOCK(&users);
07883
07884 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
07885
07886 if (cfg) {
07887
07888
07889 if (!(ucontext = ast_variable_retrieve(cfg, "general", "userscontext")))
07890 ucontext = "default";
07891 ast_copy_string(userscontext, ucontext, sizeof(userscontext));
07892
07893 if (!(astattach = ast_variable_retrieve(cfg, "general", "attach")))
07894 astattach = "yes";
07895 ast_set2_flag((&globalflags), ast_true(astattach), VM_ATTACH);
07896
07897 if (!(astsearch = ast_variable_retrieve(cfg, "general", "searchcontexts")))
07898 astsearch = "no";
07899 ast_set2_flag((&globalflags), ast_true(astsearch), VM_SEARCH);
07900
07901 volgain = 0.0;
07902 if ((volgainstr = ast_variable_retrieve(cfg, "general", "volgain")))
07903 sscanf(volgainstr, "%lf", &volgain);
07904
07905 #ifdef ODBC_STORAGE
07906 strcpy(odbc_database, "asterisk");
07907 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
07908 ast_copy_string(odbc_database, thresholdstr, sizeof(odbc_database));
07909 }
07910 strcpy(odbc_table, "voicemessages");
07911 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "odbctable"))) {
07912 ast_copy_string(odbc_table, thresholdstr, sizeof(odbc_table));
07913 }
07914 #endif
07915
07916 strcpy(mailcmd, SENDMAIL);
07917 if ((astmailcmd = ast_variable_retrieve(cfg, "general", "mailcmd")))
07918 ast_copy_string(mailcmd, astmailcmd, sizeof(mailcmd));
07919
07920 maxsilence = 0;
07921 if ((silencestr = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
07922 maxsilence = atoi(silencestr);
07923 if (maxsilence > 0)
07924 maxsilence *= 1000;
07925 }
07926
07927 if (!(maxmsgstr = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
07928 maxmsg = MAXMSG;
07929 } else {
07930 maxmsg = atoi(maxmsgstr);
07931 if (maxmsg <= 0) {
07932 ast_log(LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", maxmsgstr, MAXMSG);
07933 maxmsg = MAXMSG;
07934 } else if (maxmsg > MAXMSGLIMIT) {
07935 ast_log(LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, maxmsgstr);
07936 maxmsg = MAXMSGLIMIT;
07937 }
07938 }
07939
07940
07941 if ((emaildateformatstr = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
07942 ast_copy_string(emaildateformat, emaildateformatstr, sizeof(emaildateformat));
07943 }
07944
07945
07946 if ((extpc = ast_variable_retrieve(cfg, "general", "externpass"))) {
07947 ast_copy_string(ext_pass_cmd,extpc,sizeof(ext_pass_cmd));
07948 }
07949 #ifdef IMAP_STORAGE
07950
07951 if ((imap_server = ast_variable_retrieve(cfg, "general", "imapserver"))) {
07952 ast_copy_string(imapserver, imap_server, sizeof(imapserver));
07953 } else {
07954 ast_copy_string(imapserver,"localhost", sizeof(imapserver));
07955 }
07956
07957 if ((imap_port = ast_variable_retrieve(cfg, "general", "imapport"))) {
07958 ast_copy_string(imapport, imap_port, sizeof(imapport));
07959 } else {
07960 ast_copy_string(imapport,"143", sizeof(imapport));
07961 }
07962
07963 if ((imap_flags = ast_variable_retrieve(cfg, "general", "imapflags"))) {
07964 ast_copy_string(imapflags, imap_flags, sizeof(imapflags));
07965 }
07966
07967 if ((auth_user = ast_variable_retrieve(cfg, "general", "authuser"))) {
07968 ast_copy_string(authuser, auth_user, sizeof(authuser));
07969 }
07970
07971 if ((auth_password = ast_variable_retrieve(cfg, "general", "authpassword"))) {
07972 ast_copy_string(authpassword, auth_password, sizeof(authpassword));
07973 }
07974
07975 if ((expunge_on_hangup = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
07976 if (ast_false(expunge_on_hangup))
07977 expungeonhangup = 0;
07978 else
07979 expungeonhangup = 1;
07980 } else {
07981 expungeonhangup = 1;
07982 }
07983
07984 if ((imap_folder = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
07985 ast_copy_string(imapfolder, imap_folder, sizeof(imapfolder));
07986 } else {
07987 ast_copy_string(imapfolder,"INBOX", sizeof(imapfolder));
07988 }
07989
07990
07991
07992
07993
07994
07995 if ((imap_timeout = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
07996 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(imap_timeout)));
07997 } else {
07998 mail_parameters(NIL, SET_READTIMEOUT, (void *) DEFAULT_IMAP_TCP_TIMEOUT);
07999 }
08000
08001 if ((imap_timeout = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
08002 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(imap_timeout)));
08003 } else {
08004 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) DEFAULT_IMAP_TCP_TIMEOUT);
08005 }
08006
08007 if ((imap_timeout = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
08008 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(imap_timeout)));
08009 } else {
08010 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) DEFAULT_IMAP_TCP_TIMEOUT);
08011 }
08012
08013 if ((imap_timeout = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
08014 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(imap_timeout)));
08015 } else {
08016 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) DEFAULT_IMAP_TCP_TIMEOUT);
08017 }
08018
08019 #endif
08020
08021
08022 if ((notifystr = ast_variable_retrieve(cfg, "general", "externnotify"))) {
08023 ast_copy_string(externnotify, notifystr, sizeof(externnotify));
08024 if (option_debug > 2)
08025 ast_log(LOG_DEBUG, "found externnotify: %s\n", externnotify);
08026 if (!strcasecmp(externnotify, "smdi")) {
08027 if (option_debug)
08028 ast_log(LOG_DEBUG, "Using SMDI for external voicemail notification\n");
08029 if ((smdistr = ast_variable_retrieve(cfg, "general", "smdiport"))) {
08030 smdi_iface = ast_smdi_interface_find(smdistr);
08031 } else {
08032 if (option_debug)
08033 ast_log(LOG_DEBUG, "No SMDI interface set, trying default (/dev/ttyS0)\n");
08034 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
08035 }
08036
08037 if (!smdi_iface) {
08038 ast_log(LOG_ERROR, "No valid SMDI interface specfied, disabling external voicemail notification\n");
08039 externnotify[0] = '\0';
08040 }
08041 }
08042 } else {
08043 externnotify[0] = '\0';
08044 }
08045
08046
08047 silencethreshold = 256;
08048 if ((thresholdstr = ast_variable_retrieve(cfg, "general", "silencethreshold")))
08049 silencethreshold = atoi(thresholdstr);
08050
08051 if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail")))
08052 astemail = ASTERISK_USERNAME;
08053 ast_copy_string(serveremail, astemail, sizeof(serveremail));
08054
08055 vmmaxmessage = 0;
08056 if ((s = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
08057 if (sscanf(s, "%d", &x) == 1) {
08058 vmmaxmessage = x;
08059 } else {
08060 ast_log(LOG_WARNING, "Invalid max message time length\n");
08061 }
08062 }
08063
08064 vmminmessage = 0;
08065 if ((s = ast_variable_retrieve(cfg, "general", "minmessage"))) {
08066 if (sscanf(s, "%d", &x) == 1) {
08067 vmminmessage = x;
08068 if (maxsilence <= vmminmessage)
08069 ast_log(LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
08070 } else {
08071 ast_log(LOG_WARNING, "Invalid min message time length\n");
08072 }
08073 }
08074 fmt = ast_variable_retrieve(cfg, "general", "format");
08075 if (!fmt)
08076 fmt = "wav";
08077 ast_copy_string(vmfmts, fmt, sizeof(vmfmts));
08078
08079 skipms = 3000;
08080 if ((s = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
08081 if (sscanf(s, "%d", &x) == 1) {
08082 maxgreet = x;
08083 } else {
08084 ast_log(LOG_WARNING, "Invalid max message greeting length\n");
08085 }
08086 }
08087
08088 if ((s = ast_variable_retrieve(cfg, "general", "skipms"))) {
08089 if (sscanf(s, "%d", &x) == 1) {
08090 skipms = x;
08091 } else {
08092 ast_log(LOG_WARNING, "Invalid skipms value\n");
08093 }
08094 }
08095
08096 maxlogins = 3;
08097 if ((s = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
08098 if (sscanf(s, "%d", &x) == 1) {
08099 maxlogins = x;
08100 } else {
08101 ast_log(LOG_WARNING, "Invalid max failed login attempts\n");
08102 }
08103 }
08104
08105
08106 if (!(astforcename = ast_variable_retrieve(cfg, "general", "forcename")))
08107 astforcename = "no";
08108 ast_set2_flag((&globalflags), ast_true(astforcename), VM_FORCENAME);
08109
08110
08111 if (!(astforcegreet = ast_variable_retrieve(cfg, "general", "forcegreetings")))
08112 astforcegreet = "no";
08113 ast_set2_flag((&globalflags), ast_true(astforcegreet), VM_FORCEGREET);
08114
08115 if ((s = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))){
08116 if (option_debug > 2)
08117 ast_log(LOG_DEBUG,"VM_CID Internal context string: %s\n",s);
08118 stringp = ast_strdupa(s);
08119 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
08120 if (!ast_strlen_zero(stringp)) {
08121 q = strsep(&stringp,",");
08122 while ((*q == ' ')||(*q == '\t'))
08123 q++;
08124 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
08125 if (option_debug > 2)
08126 ast_log(LOG_DEBUG,"VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
08127 } else {
08128 cidinternalcontexts[x][0] = '\0';
08129 }
08130 }
08131 }
08132 if (!(astreview = ast_variable_retrieve(cfg, "general", "review"))){
08133 if (option_debug)
08134 ast_log(LOG_DEBUG,"VM Review Option disabled globally\n");
08135 astreview = "no";
08136 }
08137 ast_set2_flag((&globalflags), ast_true(astreview), VM_REVIEW);
08138
08139
08140 if (!(asttempgreetwarn = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
08141 if (option_debug)
08142 ast_log(LOG_DEBUG, "VM Temperary Greeting Reminder Option disabled globally\n");
08143 asttempgreetwarn = "no";
08144 } else {
08145 if (option_debug)
08146 ast_log(LOG_DEBUG, "VM Temperary Greeting Reminder Option enabled globally\n");
08147 }
08148 ast_set2_flag((&globalflags), ast_true(asttempgreetwarn), VM_TEMPGREETWARN);
08149
08150 if (!(astcallop = ast_variable_retrieve(cfg, "general", "operator"))){
08151 if (option_debug)
08152 ast_log(LOG_DEBUG,"VM Operator break disabled globally\n");
08153 astcallop = "no";
08154 }
08155 ast_set2_flag((&globalflags), ast_true(astcallop), VM_OPERATOR);
08156
08157 if (!(astsaycid = ast_variable_retrieve(cfg, "general", "saycid"))) {
08158 if (option_debug)
08159 ast_log(LOG_DEBUG,"VM CID Info before msg disabled globally\n");
08160 astsaycid = "no";
08161 }
08162 ast_set2_flag((&globalflags), ast_true(astsaycid), VM_SAYCID);
08163
08164 if (!(send_voicemail = ast_variable_retrieve(cfg,"general", "sendvoicemail"))){
08165 if (option_debug)
08166 ast_log(LOG_DEBUG,"Send Voicemail msg disabled globally\n");
08167 send_voicemail = "no";
08168 }
08169 ast_set2_flag((&globalflags), ast_true(send_voicemail), VM_SVMAIL);
08170
08171 if (!(asthearenv = ast_variable_retrieve(cfg, "general", "envelope"))) {
08172 if (option_debug)
08173 ast_log(LOG_DEBUG,"ENVELOPE before msg enabled globally\n");
08174 asthearenv = "yes";
08175 }
08176 ast_set2_flag((&globalflags), ast_true(asthearenv), VM_ENVELOPE);
08177
08178 if (!(astsaydurationinfo = ast_variable_retrieve(cfg, "general", "sayduration"))) {
08179 if (option_debug)
08180 ast_log(LOG_DEBUG,"Duration info before msg enabled globally\n");
08181 astsaydurationinfo = "yes";
08182 }
08183 ast_set2_flag((&globalflags), ast_true(astsaydurationinfo), VM_SAYDURATION);
08184
08185 saydurationminfo = 2;
08186 if ((astsaydurationminfo = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
08187 if (sscanf(astsaydurationminfo, "%d", &x) == 1) {
08188 saydurationminfo = x;
08189 } else {
08190 ast_log(LOG_WARNING, "Invalid min duration for say duration\n");
08191 }
08192 }
08193
08194 if (!(astskipcmd = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
08195 if (option_debug)
08196 ast_log(LOG_DEBUG,"We are not going to skip to the next msg after save/delete\n");
08197 astskipcmd = "no";
08198 }
08199 ast_set2_flag((&globalflags), ast_true(astskipcmd), VM_SKIPAFTERCMD);
08200
08201 if ((dialoutcxt = ast_variable_retrieve(cfg, "general", "dialout"))) {
08202 ast_copy_string(dialcontext, dialoutcxt, sizeof(dialcontext));
08203 if (option_debug)
08204 ast_log(LOG_DEBUG, "found dialout context: %s\n", dialcontext);
08205 } else {
08206 dialcontext[0] = '\0';
08207 }
08208
08209 if ((callbackcxt = ast_variable_retrieve(cfg, "general", "callback"))) {
08210 ast_copy_string(callcontext, callbackcxt, sizeof(callcontext));
08211 if (option_debug)
08212 ast_log(LOG_DEBUG, "found callback context: %s\n", callcontext);
08213 } else {
08214 callcontext[0] = '\0';
08215 }
08216
08217 if ((exitcxt = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
08218 ast_copy_string(exitcontext, exitcxt, sizeof(exitcontext));
08219 if (option_debug)
08220 ast_log(LOG_DEBUG, "found operator context: %s\n", exitcontext);
08221 } else {
08222 exitcontext[0] = '\0';
08223 }
08224
08225 if (!(astdirfwd = ast_variable_retrieve(cfg, "general", "usedirectory")))
08226 astdirfwd = "no";
08227 ast_set2_flag((&globalflags), ast_true(astdirfwd), VM_DIRECFORWARD);
08228 if ((ucfg = ast_config_load("users.conf"))) {
08229 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
08230 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
08231 continue;
08232 if ((cur = find_or_create(userscontext, cat))) {
08233 populate_defaults(cur);
08234 apply_options_full(cur, ast_variable_browse(ucfg, cat));
08235 ast_copy_string(cur->context, userscontext, sizeof(cur->context));
08236 }
08237 }
08238 ast_config_destroy(ucfg);
08239 }
08240 cat = ast_category_browse(cfg, NULL);
08241 while (cat) {
08242 if (strcasecmp(cat, "general")) {
08243 var = ast_variable_browse(cfg, cat);
08244 if (strcasecmp(cat, "zonemessages")) {
08245
08246 while (var) {
08247 append_mailbox(cat, var->name, var->value);
08248 var = var->next;
08249 }
08250 } else {
08251
08252 while (var) {
08253 struct vm_zone *z;
08254 if ((z = ast_malloc(sizeof(*z)))) {
08255 char *msg_format, *timezone;
08256 msg_format = ast_strdupa(var->value);
08257 timezone = strsep(&msg_format, "|");
08258 if (msg_format) {
08259 ast_copy_string(z->name, var->name, sizeof(z->name));
08260 ast_copy_string(z->timezone, timezone, sizeof(z->timezone));
08261 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
08262 AST_LIST_LOCK(&zones);
08263 AST_LIST_INSERT_HEAD(&zones, z, list);
08264 AST_LIST_UNLOCK(&zones);
08265 } else {
08266 ast_log(LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
08267 free(z);
08268 }
08269 } else {
08270 free(z);
08271 AST_LIST_UNLOCK(&users);
08272 ast_config_destroy(cfg);
08273 return -1;
08274 }
08275 var = var->next;
08276 }
08277 }
08278 }
08279 cat = ast_category_browse(cfg, cat);
08280 }
08281 memset(fromstring,0,sizeof(fromstring));
08282 memset(pagerfromstring,0,sizeof(pagerfromstring));
08283 memset(emailtitle,0,sizeof(emailtitle));
08284 strcpy(charset, "ISO-8859-1");
08285 if (emailbody) {
08286 free(emailbody);
08287 emailbody = NULL;
08288 }
08289 if (emailsubject) {
08290 free(emailsubject);
08291 emailsubject = NULL;
08292 }
08293 if (pagerbody) {
08294 free(pagerbody);
08295 pagerbody = NULL;
08296 }
08297 if (pagersubject) {
08298 free(pagersubject);
08299 pagersubject = NULL;
08300 }
08301 if ((s = ast_variable_retrieve(cfg, "general", "pbxskip")))
08302 ast_set2_flag((&globalflags), ast_true(s), VM_PBXSKIP);
08303 if ((s = ast_variable_retrieve(cfg, "general", "fromstring")))
08304 ast_copy_string(fromstring,s,sizeof(fromstring));
08305 if ((s = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
08306 ast_copy_string(pagerfromstring,s,sizeof(pagerfromstring));
08307 if ((s = ast_variable_retrieve(cfg, "general", "charset")))
08308 ast_copy_string(charset,s,sizeof(charset));
08309 if ((s = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
08310 sscanf(s, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
08311 for (x = 0; x < 4; x++) {
08312 memcpy(&adsifdn[x], &tmpadsi[x], 1);
08313 }
08314 }
08315 if ((s = ast_variable_retrieve(cfg, "general", "adsisec"))) {
08316 sscanf(s, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
08317 for (x = 0; x < 4; x++) {
08318 memcpy(&adsisec[x], &tmpadsi[x], 1);
08319 }
08320 }
08321 if ((s = ast_variable_retrieve(cfg, "general", "adsiver")))
08322 if (atoi(s)) {
08323 adsiver = atoi(s);
08324 }
08325 if ((s = ast_variable_retrieve(cfg, "general", "emailtitle"))) {
08326 ast_log(LOG_NOTICE, "Keyword 'emailtitle' is DEPRECATED, please use 'emailsubject' instead.\n");
08327 ast_copy_string(emailtitle,s,sizeof(emailtitle));
08328 }
08329 if ((s = ast_variable_retrieve(cfg, "general", "emailsubject")))
08330 emailsubject = ast_strdup(s);
08331 if ((s = ast_variable_retrieve(cfg, "general", "emailbody"))) {
08332 char *tmpread, *tmpwrite;
08333 emailbody = ast_strdup(s);
08334
08335
08336 tmpread = tmpwrite = emailbody;
08337 while ((tmpwrite = strchr(tmpread,'\\'))) {
08338 switch (tmpwrite[1]) {
08339 case 'r':
08340 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
08341 *tmpwrite = '\r';
08342 break;
08343 case 'n':
08344 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
08345 *tmpwrite = '\n';
08346 break;
08347 case 't':
08348 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
08349 *tmpwrite = '\t';
08350 break;
08351 default:
08352 ast_log(LOG_NOTICE, "Substitution routine does not support this character: %c\n", tmpwrite[1]);
08353 }
08354 tmpread = tmpwrite + 1;
08355 }
08356 }
08357 if ((s = ast_variable_retrieve(cfg, "general", "pagersubject")))
08358 pagersubject = ast_strdup(s);
08359 if ((s = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
08360 char *tmpread, *tmpwrite;
08361 pagerbody = ast_strdup(s);
08362
08363
08364 tmpread = tmpwrite = pagerbody;
08365 while ((tmpwrite = strchr(tmpread, '\\'))) {
08366 switch (tmpwrite[1]) {
08367 case 'r':
08368 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
08369 *tmpwrite = '\r';
08370 break;
08371 case 'n':
08372 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
08373 *tmpwrite = '\n';
08374 break;
08375 case 't':
08376 memmove(tmpwrite + 1, tmpwrite + 2, strlen(tmpwrite + 2) + 1);
08377 *tmpwrite = '\t';
08378 break;
08379 default:
08380 ast_log(LOG_NOTICE, "Substitution routine does not support this character: %c\n", tmpwrite[1]);
08381 }
08382 tmpread = tmpwrite + 1;
08383 }
08384 }
08385 AST_LIST_UNLOCK(&users);
08386 ast_config_destroy(cfg);
08387 return 0;
08388 } else {
08389 AST_LIST_UNLOCK(&users);
08390 ast_log(LOG_WARNING, "Failed to load configuration file.\n");
08391 return 0;
08392 }
08393 }
08394
08395 static int reload(void)
08396 {
08397 return(load_config());
08398 }
08399
08400 static int unload_module(void)
08401 {
08402 int res;
08403
08404 res = ast_unregister_application(app);
08405 res |= ast_unregister_application(app2);
08406 res |= ast_unregister_application(app3);
08407 res |= ast_unregister_application(app4);
08408 ast_cli_unregister_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
08409 ast_uninstall_vm_functions();
08410
08411 ast_module_user_hangup_all();
08412
08413 return res;
08414 }
08415
08416 static int load_module(void)
08417 {
08418 int res;
08419 char *adsi_loaded = ast_module_helper("", "res_adsi.so", 0, 0, 0, 0);
08420 free(adsi_loaded);
08421 if (!adsi_loaded) {
08422
08423 adsi_loaded = ast_module_helper("", "res_adsi", 0, 0, 0, 0);
08424 ast_free(adsi_loaded);
08425 if (!adsi_loaded) {
08426 ast_log(LOG_ERROR, "app_voicemail.so depends upon res_adsi.so\n");
08427 return AST_MODULE_LOAD_DECLINE;
08428 }
08429 }
08430
08431 my_umask = umask(0);
08432 umask(my_umask);
08433 res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
08434 res |= ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
08435 res |= ast_register_application(app3, vm_box_exists, synopsis_vm_box_exists, descrip_vm_box_exists);
08436 res |= ast_register_application(app4, vmauthenticate, synopsis_vmauthenticate, descrip_vmauthenticate);
08437 if (res)
08438 return(res);
08439
08440 if ((res=load_config())) {
08441 return(res);
08442 }
08443
08444 ast_cli_register_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
08445
08446
08447 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
08448
08449 ast_install_vm_functions(has_voicemail, inboxcount, messagecount);
08450
08451 return res;
08452 }
08453
08454 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
08455 {
08456 int cmd = 0;
08457 char destination[80] = "";
08458 int retries = 0;
08459
08460 if (!num) {
08461 if (option_verbose > 2)
08462 ast_verbose( VERBOSE_PREFIX_3 "Destination number will be entered manually\n");
08463 while (retries < 3 && cmd != 't') {
08464 destination[1] = '\0';
08465 destination[0] = cmd = ast_play_and_wait(chan,"vm-enter-num-to-call");
08466 if (!cmd)
08467 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
08468 if (!cmd)
08469 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
08470 if (!cmd) {
08471 cmd = ast_waitfordigit(chan, 6000);
08472 if (cmd)
08473 destination[0] = cmd;
08474 }
08475 if (!cmd) {
08476 retries++;
08477 } else {
08478
08479 if (cmd < 0)
08480 return 0;
08481 if (cmd == '*') {
08482 if (option_verbose > 2)
08483 ast_verbose( VERBOSE_PREFIX_3 "User hit '*' to cancel outgoing call\n");
08484 return 0;
08485 }
08486 if ((cmd = ast_readstring(chan,destination + strlen(destination),sizeof(destination)-1,6000,10000,"#")) < 0)
08487 retries++;
08488 else
08489 cmd = 't';
08490 }
08491 }
08492 if (retries >= 3) {
08493 return 0;
08494 }
08495
08496 } else {
08497 if (option_verbose > 2)
08498 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
08499 ast_copy_string(destination, num, sizeof(destination));
08500 }
08501
08502 if (!ast_strlen_zero(destination)) {
08503 if (destination[strlen(destination) -1 ] == '*')
08504 return 0;
08505 if (option_verbose > 2)
08506 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
08507 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
08508 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
08509 chan->priority = 0;
08510 return 9;
08511 }
08512 return 0;
08513 }
08514
08515 static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option, signed char record_gain)
08516 {
08517 int res = 0;
08518 char filename[PATH_MAX];
08519 struct ast_config *msg_cfg = NULL;
08520 const char *origtime, *context;
08521 char *cid, *name, *num;
08522 int retries = 0;
08523
08524 vms->starting = 0;
08525 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
08526
08527
08528 make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);
08529 snprintf(filename,sizeof(filename), "%s.txt", vms->fn2);
08530 RETRIEVE(vms->curdir, vms->curmsg, vmu);
08531 msg_cfg = ast_config_load(filename);
08532 DISPOSE(vms->curdir, vms->curmsg);
08533 if (!msg_cfg) {
08534 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
08535 return 0;
08536 }
08537
08538 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
08539 ast_config_destroy(msg_cfg);
08540 return 0;
08541 }
08542
08543 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
08544
08545 context = ast_variable_retrieve(msg_cfg, "message", "context");
08546 if (!strncasecmp("macro",context,5))
08547 context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
08548 switch (option) {
08549 case 3:
08550 if (!res)
08551 res = play_message_datetime(chan, vmu, origtime, filename);
08552 if (!res)
08553 res = play_message_callerid(chan, vms, cid, context, 0);
08554
08555 res = 't';
08556 break;
08557
08558 case 2:
08559
08560 if (ast_strlen_zero(cid))
08561 break;
08562
08563 ast_callerid_parse(cid, &name, &num);
08564 while ((res > -1) && (res != 't')) {
08565 switch (res) {
08566 case '1':
08567 if (num) {
08568
08569 res = dialout(chan, vmu, num, vmu->callback);
08570 if (res) {
08571 ast_config_destroy(msg_cfg);
08572 return 9;
08573 }
08574 } else {
08575 res = '2';
08576 }
08577 break;
08578
08579 case '2':
08580
08581 if (!ast_strlen_zero(vmu->dialout)) {
08582 res = dialout(chan, vmu, NULL, vmu->dialout);
08583 if (res) {
08584 ast_config_destroy(msg_cfg);
08585 return 9;
08586 }
08587 } else {
08588 if (option_verbose > 2)
08589 ast_verbose( VERBOSE_PREFIX_3 "Caller can not specify callback number - no dialout context available\n");
08590 res = ast_play_and_wait(chan, "vm-sorry");
08591 }
08592 ast_config_destroy(msg_cfg);
08593 return res;
08594 case '*':
08595 res = 't';
08596 break;
08597 case '3':
08598 case '4':
08599 case '5':
08600 case '6':
08601 case '7':
08602 case '8':
08603 case '9':
08604 case '0':
08605
08606 res = ast_play_and_wait(chan, "vm-sorry");
08607 retries++;
08608 break;
08609 default:
08610 if (num) {
08611 if (option_verbose > 2)
08612 ast_verbose( VERBOSE_PREFIX_3 "Confirm CID number '%s' is number to use for callback\n", num);
08613 res = ast_play_and_wait(chan, "vm-num-i-have");
08614 if (!res)
08615 res = play_message_callerid(chan, vms, num, vmu->context, 1);
08616 if (!res)
08617 res = ast_play_and_wait(chan, "vm-tocallnum");
08618
08619 if (!ast_strlen_zero(vmu->dialout)) {
08620 if (!res)
08621 res = ast_play_and_wait(chan, "vm-calldiffnum");
08622 }
08623 } else {
08624 res = ast_play_and_wait(chan, "vm-nonumber");
08625 if (!ast_strlen_zero(vmu->dialout)) {
08626 if (!res)
08627 res = ast_play_and_wait(chan, "vm-toenternumber");
08628 }
08629 }
08630 if (!res)
08631 res = ast_play_and_wait(chan, "vm-star-cancel");
08632 if (!res)
08633 res = ast_waitfordigit(chan, 6000);
08634 if (!res) {
08635 retries++;
08636 if (retries > 3)
08637 res = 't';
08638 }
08639 break;
08640
08641 }
08642 if (res == 't')
08643 res = 0;
08644 else if (res == '*')
08645 res = -1;
08646 }
08647 break;
08648
08649 case 1:
08650
08651 if (ast_strlen_zero(cid))
08652 break;
08653
08654 ast_callerid_parse(cid, &name, &num);
08655 if (!num) {
08656 if (option_verbose > 2)
08657 ast_verbose(VERBOSE_PREFIX_3 "No CID number available, no reply sent\n");
08658 if (!res)
08659 res = ast_play_and_wait(chan, "vm-nonumber");
08660 ast_config_destroy(msg_cfg);
08661 return res;
08662 } else {
08663 struct ast_vm_user vmu2;
08664 if (find_user(&vmu2, vmu->context, num)) {
08665 struct leave_vm_options leave_options;
08666 char mailbox[AST_MAX_EXTENSION * 2 + 2];
08667 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
08668
08669 if (option_verbose > 2)
08670 ast_verbose(VERBOSE_PREFIX_3 "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
08671
08672 memset(&leave_options, 0, sizeof(leave_options));
08673 leave_options.record_gain = record_gain;
08674 res = leave_voicemail(chan, mailbox, &leave_options);
08675 if (!res)
08676 res = 't';
08677 ast_config_destroy(msg_cfg);
08678 return res;
08679 } else {
08680
08681 if (option_verbose > 2)
08682 ast_verbose( VERBOSE_PREFIX_3 "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
08683 ast_play_and_wait(chan, "vm-nobox");
08684 res = 't';
08685 ast_config_destroy(msg_cfg);
08686 return res;
08687 }
08688 }
08689 res = 0;
08690
08691 break;
08692 }
08693
08694 #ifndef IMAP_STORAGE
08695 ast_config_destroy(msg_cfg);
08696
08697 if (!res) {
08698 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
08699 vms->heard[msg] = 1;
08700 res = wait_file(chan, vms, vms->fn);
08701 }
08702 #endif
08703 return res;
08704 }
08705
08706 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
08707 int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
08708 signed char record_gain, struct vm_state *vms)
08709 {
08710
08711 int res = 0;
08712 int cmd = 0;
08713 int max_attempts = 3;
08714 int attempts = 0;
08715 int recorded = 0;
08716 int message_exists = 0;
08717 signed char zero_gain = 0;
08718 char tempfile[PATH_MAX];
08719 char *acceptdtmf = "#";
08720 char *canceldtmf = "";
08721
08722
08723
08724
08725 if (duration == NULL) {
08726 ast_log(LOG_WARNING, "Error play_record_review called without duration pointer\n");
08727 return -1;
08728 }
08729
08730 if (!outsidecaller)
08731 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
08732 else
08733 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
08734
08735 cmd = '3';
08736
08737 while ((cmd >= 0) && (cmd != 't')) {
08738 switch (cmd) {
08739 case '1':
08740 if (!message_exists) {
08741
08742 cmd = '3';
08743 break;
08744 } else {
08745
08746 if (option_verbose > 2)
08747 ast_verbose(VERBOSE_PREFIX_3 "Saving message as is\n");
08748 if (!outsidecaller)
08749 ast_filerename(tempfile, recordfile, NULL);
08750 ast_stream_and_wait(chan, "vm-msgsaved", chan->language, "");
08751 if (!outsidecaller) {
08752 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms);
08753 DISPOSE(recordfile, -1);
08754 }
08755 cmd = 't';
08756 return res;
08757 }
08758 case '2':
08759
08760 if (option_verbose > 2)
08761 ast_verbose(VERBOSE_PREFIX_3 "Reviewing the message\n");
08762 cmd = ast_stream_and_wait(chan, tempfile, chan->language, AST_DIGIT_ANY);
08763 break;
08764 case '3':
08765 message_exists = 0;
08766
08767 if (recorded == 1) {
08768 if (option_verbose > 2)
08769 ast_verbose(VERBOSE_PREFIX_3 "Re-recording the message\n");
08770 } else {
08771 if (option_verbose > 2)
08772 ast_verbose(VERBOSE_PREFIX_3 "Recording the message\n");
08773 }
08774 if (recorded && outsidecaller) {
08775 cmd = ast_play_and_wait(chan, INTRO);
08776 cmd = ast_play_and_wait(chan, "beep");
08777 }
08778 recorded = 1;
08779
08780 if (record_gain)
08781 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
08782 if (ast_test_flag(vmu, VM_OPERATOR))
08783 canceldtmf = "0";
08784 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
08785 if (record_gain)
08786 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
08787 if (cmd == -1) {
08788
08789 if (!outsidecaller) {
08790
08791 ast_filedelete(tempfile, NULL);
08792 }
08793 return cmd;
08794 }
08795 if (cmd == '0') {
08796 break;
08797 } else if (cmd == '*') {
08798 break;
08799 }
08800 #if 0
08801 else if (vmu->review && (*duration < 5)) {
08802
08803 if (option_verbose > 2)
08804 ast_verbose(VERBOSE_PREFIX_3 "Message too short\n");
08805 cmd = ast_play_and_wait(chan, "vm-tooshort");
08806 cmd = ast_filedelete(tempfile, NULL);
08807 break;
08808 }
08809 else if (vmu->review && (cmd == 2 && *duration < (maxsilence + 3))) {
08810
08811 if (option_verbose > 2)
08812 ast_verbose(VERBOSE_PREFIX_3 "Nothing recorded\n");
08813 cmd = ast_filedelete(tempfile, NULL);
08814 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
08815 if (!cmd)
08816 cmd = ast_play_and_wait(chan, "vm-speakup");
08817 break;
08818 }
08819 #endif
08820 else {
08821
08822 message_exists = 1;
08823 cmd = 0;
08824 }
08825 break;
08826 case '4':
08827 case '5':
08828 case '6':
08829 case '7':
08830 case '8':
08831 case '9':
08832 case '*':
08833 case '#':
08834 cmd = ast_play_and_wait(chan, "vm-sorry");
08835 break;
08836 #if 0
08837
08838
08839 case '*':
08840
08841 cmd = ast_play_and_wait(chan, "vm-deleted");
08842 cmd = ast_filedelete(tempfile, NULL);
08843 if (outsidecaller) {
08844 res = vm_exec(chan, NULL);
08845 return res;
08846 }
08847 else
08848 return 1;
08849 #endif
08850 case '0':
08851 if (!ast_test_flag(vmu, VM_OPERATOR)) {
08852 cmd = ast_play_and_wait(chan, "vm-sorry");
08853 break;
08854 }
08855 if (message_exists || recorded) {
08856 cmd = ast_play_and_wait(chan, "vm-saveoper");
08857 if (!cmd)
08858 cmd = ast_waitfordigit(chan, 3000);
08859 if (cmd == '1') {
08860 ast_play_and_wait(chan, "vm-msgsaved");
08861 cmd = '0';
08862 } else {
08863 ast_play_and_wait(chan, "vm-deleted");
08864 DELETE(recordfile, -1, recordfile, vmu);
08865 cmd = '0';
08866 }
08867 }
08868 return cmd;
08869 default:
08870
08871
08872
08873 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
08874 return cmd;
08875 if (message_exists) {
08876 cmd = ast_play_and_wait(chan, "vm-review");
08877 }
08878 else {
08879 cmd = ast_play_and_wait(chan, "vm-torerecord");
08880 if (!cmd)
08881 cmd = ast_waitfordigit(chan, 600);
08882 }
08883
08884 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
08885 cmd = ast_play_and_wait(chan, "vm-reachoper");
08886 if (!cmd)
08887 cmd = ast_waitfordigit(chan, 600);
08888 }
08889 #if 0
08890 if (!cmd)
08891 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
08892 #endif
08893 if (!cmd)
08894 cmd = ast_waitfordigit(chan, 6000);
08895 if (!cmd) {
08896 attempts++;
08897 }
08898 if (attempts > max_attempts) {
08899 cmd = 't';
08900 }
08901 }
08902 }
08903 if (outsidecaller)
08904 ast_play_and_wait(chan, "vm-goodbye");
08905 if (cmd == 't')
08906 cmd = 0;
08907 return cmd;
08908 }
08909
08910
08911
08912
08913
08914 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
08915 .load = load_module,
08916 .unload = unload_module,
08917 .reload = reload,
08918 );