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
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 #include "asterisk.h"
00072
00073 #ifdef IMAP_STORAGE
00074 #include <ctype.h>
00075 #include <signal.h>
00076 #include <pwd.h>
00077 #ifdef USE_SYSTEM_IMAP
00078 #include <imap/c-client.h>
00079 #include <imap/imap4r1.h>
00080 #include <imap/linkage.h>
00081 #elif defined (USE_SYSTEM_CCLIENT)
00082 #include <c-client/c-client.h>
00083 #include <c-client/imap4r1.h>
00084 #include <c-client/linkage.h>
00085 #else
00086 #include "c-client.h"
00087 #include "imap4r1.h"
00088 #include "linkage.h"
00089 #endif
00090 #endif
00091
00092 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 262339 $")
00093
00094 #include "asterisk/paths.h"
00095 #include <sys/time.h>
00096 #include <sys/stat.h>
00097 #include <sys/mman.h>
00098 #include <time.h>
00099 #include <dirent.h>
00100
00101 #include "asterisk/logger.h"
00102 #include "asterisk/lock.h"
00103 #include "asterisk/file.h"
00104 #include "asterisk/channel.h"
00105 #include "asterisk/pbx.h"
00106 #include "asterisk/config.h"
00107 #include "asterisk/say.h"
00108 #include "asterisk/module.h"
00109 #include "asterisk/adsi.h"
00110 #include "asterisk/app.h"
00111 #include "asterisk/manager.h"
00112 #include "asterisk/dsp.h"
00113 #include "asterisk/localtime.h"
00114 #include "asterisk/cli.h"
00115 #include "asterisk/utils.h"
00116 #include "asterisk/stringfields.h"
00117 #include "asterisk/smdi.h"
00118 #include "asterisk/astobj2.h"
00119 #include "asterisk/event.h"
00120 #include "asterisk/taskprocessor.h"
00121
00122 #ifdef ODBC_STORAGE
00123 #include "asterisk/res_odbc.h"
00124 #endif
00125
00126 #ifdef IMAP_STORAGE
00127 #include "asterisk/threadstorage.h"
00128
00129 static char imapserver[48];
00130 static char imapport[8];
00131 static char imapflags[128];
00132 static char imapfolder[64];
00133 static char imapparentfolder[64] = "\0";
00134 static char greetingfolder[64];
00135 static char authuser[32];
00136 static char authpassword[42];
00137 static int imapversion = 1;
00138
00139 static int expungeonhangup = 1;
00140 static int imapgreetings = 0;
00141 static char delimiter = '\0';
00142
00143 struct vm_state;
00144 struct ast_vm_user;
00145
00146 AST_THREADSTORAGE(ts_vmstate);
00147
00148
00149 static int init_mailstream(struct vm_state *vms, int box);
00150 static void write_file(char *filename, char *buffer, unsigned long len);
00151 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00152 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00153 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00154 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00155 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00156 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00157 static void vmstate_insert(struct vm_state *vms);
00158 static void vmstate_delete(struct vm_state *vms);
00159 static void set_update(MAILSTREAM * stream);
00160 static void init_vm_state(struct vm_state *vms);
00161 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
00162 static void get_mailbox_delimiter(MAILSTREAM *stream);
00163 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00164 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00165 static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag);
00166 static void update_messages_by_imapuser(const char *user, unsigned long number);
00167 static int vm_delete(char *file);
00168
00169 static int imap_remove_file (char *dir, int msgnum);
00170 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00171 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00172 static void check_quota(struct vm_state *vms, char *mailbox);
00173 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00174 struct vmstate {
00175 struct vm_state *vms;
00176 AST_LIST_ENTRY(vmstate) list;
00177 };
00178
00179 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00180
00181 #endif
00182
00183 #define SMDI_MWI_WAIT_TIMEOUT 1000
00184
00185 #define COMMAND_TIMEOUT 5000
00186
00187 #define VOICEMAIL_DIR_MODE 0777
00188 #define VOICEMAIL_FILE_MODE 0666
00189 #define CHUNKSIZE 65536
00190
00191 #define VOICEMAIL_CONFIG "voicemail.conf"
00192 #define ASTERISK_USERNAME "asterisk"
00193
00194
00195
00196
00197 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00198 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00199 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00200 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00201 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00202 #define VALID_DTMF "1234567890*#"
00203
00204
00205
00206 #define SENDMAIL "/usr/sbin/sendmail -t"
00207
00208 #define INTRO "vm-intro"
00209
00210 #define MAXMSG 100
00211 #define MAXMSGLIMIT 9999
00212
00213 #define MINPASSWORD 0
00214
00215 #define BASELINELEN 72
00216 #define BASEMAXINLINE 256
00217 #ifdef IMAP_STORAGE
00218 #define ENDL "\r\n"
00219 #else
00220 #define ENDL "\n"
00221 #endif
00222
00223 #define MAX_DATETIME_FORMAT 512
00224 #define MAX_NUM_CID_CONTEXTS 10
00225
00226 #define VM_REVIEW (1 << 0)
00227 #define VM_OPERATOR (1 << 1)
00228 #define VM_SAYCID (1 << 2)
00229 #define VM_SVMAIL (1 << 3)
00230 #define VM_ENVELOPE (1 << 4)
00231 #define VM_SAYDURATION (1 << 5)
00232 #define VM_SKIPAFTERCMD (1 << 6)
00233 #define VM_FORCENAME (1 << 7)
00234 #define VM_FORCEGREET (1 << 8)
00235 #define VM_PBXSKIP (1 << 9)
00236 #define VM_DIRECFORWARD (1 << 10)
00237 #define VM_ATTACH (1 << 11)
00238 #define VM_DELETE (1 << 12)
00239 #define VM_ALLOCED (1 << 13)
00240 #define VM_SEARCH (1 << 14)
00241 #define VM_TEMPGREETWARN (1 << 15)
00242 #define VM_MOVEHEARD (1 << 16)
00243 #define VM_MESSAGEWRAP (1 << 17)
00244 #define VM_FWDURGAUTO (1 << 18)
00245 #define ERROR_LOCK_PATH -100
00246 #define OPERATOR_EXIT 300
00247
00248
00249 enum {
00250 NEW_FOLDER,
00251 OLD_FOLDER,
00252 WORK_FOLDER,
00253 FAMILY_FOLDER,
00254 FRIENDS_FOLDER,
00255 GREETINGS_FOLDER
00256 } vm_box;
00257
00258 enum {
00259 OPT_SILENT = (1 << 0),
00260 OPT_BUSY_GREETING = (1 << 1),
00261 OPT_UNAVAIL_GREETING = (1 << 2),
00262 OPT_RECORDGAIN = (1 << 3),
00263 OPT_PREPEND_MAILBOX = (1 << 4),
00264 OPT_AUTOPLAY = (1 << 6),
00265 OPT_DTMFEXIT = (1 << 7),
00266 OPT_MESSAGE_Urgent = (1 << 8),
00267 OPT_MESSAGE_PRIORITY = (1 << 9)
00268 } vm_option_flags;
00269
00270 enum {
00271 OPT_ARG_RECORDGAIN = 0,
00272 OPT_ARG_PLAYFOLDER = 1,
00273 OPT_ARG_DTMFEXIT = 2,
00274
00275 OPT_ARG_ARRAY_SIZE = 3,
00276 } vm_option_args;
00277
00278 AST_APP_OPTIONS(vm_app_options, {
00279 AST_APP_OPTION('s', OPT_SILENT),
00280 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00281 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00282 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00283 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00284 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00285 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00286 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
00287 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
00288 });
00289
00290 static int load_config(int reload);
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
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375 struct baseio {
00376 int iocp;
00377 int iolen;
00378 int linelength;
00379 int ateof;
00380 unsigned char iobuf[BASEMAXINLINE];
00381 };
00382
00383
00384
00385 struct ast_vm_user {
00386 char context[AST_MAX_CONTEXT];
00387 char mailbox[AST_MAX_EXTENSION];
00388 char password[80];
00389 char fullname[80];
00390 char email[80];
00391 char pager[80];
00392 char serveremail[80];
00393 char mailcmd[160];
00394 char language[MAX_LANGUAGE];
00395 char zonetag[80];
00396 char callback[80];
00397 char dialout[80];
00398 char uniqueid[80];
00399 char exit[80];
00400 char attachfmt[20];
00401 unsigned int flags;
00402 int saydurationm;
00403 int maxmsg;
00404 int maxdeletedmsg;
00405 int maxsecs;
00406 #ifdef IMAP_STORAGE
00407 char imapuser[80];
00408 char imappassword[80];
00409 char imapvmshareid[80];
00410 int imapversion;
00411 #endif
00412 double volgain;
00413 AST_LIST_ENTRY(ast_vm_user) list;
00414 };
00415
00416
00417 struct vm_zone {
00418 AST_LIST_ENTRY(vm_zone) list;
00419 char name[80];
00420 char timezone[80];
00421 char msg_format[512];
00422 };
00423
00424 #define VMSTATE_MAX_MSG_ARRAY 256
00425
00426
00427 struct vm_state {
00428 char curbox[80];
00429 char username[80];
00430 char context[80];
00431 char curdir[PATH_MAX];
00432 char vmbox[PATH_MAX];
00433 char fn[PATH_MAX];
00434 char intro[PATH_MAX];
00435 int *deleted;
00436 int *heard;
00437 int curmsg;
00438 int lastmsg;
00439 int newmessages;
00440 int oldmessages;
00441 int urgentmessages;
00442 int starting;
00443 int repeats;
00444 #ifdef IMAP_STORAGE
00445 ast_mutex_t lock;
00446 int updated;
00447 long msgArray[VMSTATE_MAX_MSG_ARRAY];
00448 MAILSTREAM *mailstream;
00449 int vmArrayIndex;
00450 char imapuser[80];
00451 int imapversion;
00452 int interactive;
00453 char introfn[PATH_MAX];
00454 unsigned int quota_limit;
00455 unsigned int quota_usage;
00456 struct vm_state *persist_vms;
00457 #endif
00458 };
00459
00460 #ifdef ODBC_STORAGE
00461 static char odbc_database[80];
00462 static char odbc_table[80];
00463 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00464 #define DISPOSE(a,b) remove_file(a,b)
00465 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00466 #define EXISTS(a,b,c,d) (message_exists(a,b))
00467 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00468 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00469 #define DELETE(a,b,c,d) (delete_file(a,b))
00470 #else
00471 #ifdef IMAP_STORAGE
00472 #define DISPOSE(a,b) (imap_remove_file(a,b))
00473 #define STORE(a,b,c,d,e,f,g,h,i,j) (imap_store_file(a,b,c,d,e,f,g,h,i,j))
00474 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00475 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00476 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00477 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00478 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00479 #else
00480 #define RETRIEVE(a,b,c,d)
00481 #define DISPOSE(a,b)
00482 #define STORE(a,b,c,d,e,f,g,h,i,j)
00483 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00484 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00485 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00486 #define DELETE(a,b,c,d) (vm_delete(c))
00487 #endif
00488 #endif
00489
00490 static char VM_SPOOL_DIR[PATH_MAX];
00491
00492 static char ext_pass_cmd[128];
00493 static char ext_pass_check_cmd[128];
00494
00495 static int my_umask;
00496
00497 #define PWDCHANGE_INTERNAL (1 << 1)
00498 #define PWDCHANGE_EXTERNAL (1 << 2)
00499 static int pwdchange = PWDCHANGE_INTERNAL;
00500
00501 #ifdef ODBC_STORAGE
00502 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00503 #else
00504 # ifdef IMAP_STORAGE
00505 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00506 # else
00507 # define tdesc "Comedian Mail (Voicemail System)"
00508 # endif
00509 #endif
00510
00511 static char userscontext[AST_MAX_EXTENSION] = "default";
00512
00513 static char *addesc = "Comedian Mail";
00514
00515 static char *synopsis_vm = "Leave a Voicemail message";
00516
00517 static char *descrip_vm =
00518 " VoiceMail(mailbox[@context][&mailbox[@context]][...][,options]): This\n"
00519 "application allows the calling party to leave a message for the specified\n"
00520 "list of mailboxes. When multiple mailboxes are specified, the greeting will\n"
00521 "be taken from the first mailbox specified. Dialplan execution will stop if the\n"
00522 "specified mailbox does not exist.\n"
00523 " The Voicemail application will exit if any of the following DTMF digits are\n"
00524 "received:\n"
00525 " 0 - Jump to the 'o' extension in the current dialplan context.\n"
00526 " * - Jump to the 'a' extension in the current dialplan context.\n"
00527 " This application will set the following channel variable upon completion:\n"
00528 " VMSTATUS - This indicates the status of the execution of the VoiceMail\n"
00529 " application. The possible values are:\n"
00530 " SUCCESS | USEREXIT | FAILED\n\n"
00531 " Options:\n"
00532 " b - Play the 'busy' greeting to the calling party.\n"
00533 " d([c]) - Accept digits for a new extension in context c, if played during\n"
00534 " the greeting. Context defaults to the current context.\n"
00535 " g(#) - Use the specified amount of gain when recording the voicemail\n"
00536 " message. The units are whole-number decibels (dB).\n"
00537 " Only works on supported technologies, which is DAHDI only.\n"
00538 " s - Skip the playback of instructions for leaving a message to the\n"
00539 " calling party.\n"
00540 " u - Play the 'unavailable' greeting.\n"
00541 " U - Mark message as Urgent.\n"
00542 " P - Mark message as PRIORITY.\n";
00543
00544 static char *synopsis_vmain = "Check Voicemail messages";
00545
00546 static char *descrip_vmain =
00547 " VoiceMailMain([mailbox][@context][,options]): This application allows the\n"
00548 "calling party to check voicemail messages. A specific mailbox, and optional\n"
00549 "corresponding context, may be specified. If a mailbox is not provided, the\n"
00550 "calling party will be prompted to enter one. If a context is not specified,\n"
00551 "the 'default' context will be used.\n\n"
00552 " Options:\n"
00553 " p - Consider the mailbox parameter as a prefix to the mailbox that\n"
00554 " is entered by the caller.\n"
00555 " g(#) - Use the specified amount of gain when recording a voicemail\n"
00556 " message. The units are whole-number decibels (dB).\n"
00557 " s - Skip checking the passcode for the mailbox.\n"
00558 " a(#) - Skip folder prompt and go directly to folder specified.\n"
00559 " Accepted values are:\n"
00560 " 0 for INBOX\n"
00561 " 1 for Old\n"
00562 " 2 for Work\n"
00563 " 3 for Family\n"
00564 " 4 for Friends\n"
00565 " 5 for Cust1\n"
00566 " 6 for Cust2\n"
00567 " 7 for Cust3\n"
00568 " 8 for Cust4\n"
00569 " 9 for Cust5\n"
00570 " Defaults to 0 (INBOX).\n";
00571
00572 static char *synopsis_vm_box_exists =
00573 "Check to see if Voicemail mailbox exists";
00574
00575 static char *descrip_vm_box_exists =
00576 " MailboxExists(mailbox[@context][,options]): Check to see if the specified\n"
00577 "mailbox exists. If no voicemail context is specified, the 'default' context\n"
00578 "will be used.\n"
00579 " This application will set the following channel variable upon completion:\n"
00580 " VMBOXEXISTSSTATUS - This will contain the status of the execution of the\n"
00581 " MailboxExists application. Possible values include:\n"
00582 " SUCCESS | FAILED\n\n"
00583 " Options: (none)\n";
00584
00585 static char *synopsis_vmauthenticate = "Authenticate with Voicemail passwords";
00586
00587 static char *descrip_vmauthenticate =
00588 " VMAuthenticate([mailbox][@context][,options]): This application behaves the\n"
00589 "same way as the Authenticate application, but the passwords are taken from\n"
00590 "voicemail.conf.\n"
00591 " If the mailbox is specified, only that mailbox's password will be considered\n"
00592 "valid. If the mailbox is not specified, the channel variable AUTH_MAILBOX will\n"
00593 "be set with the authenticated mailbox.\n\n"
00594 " Options:\n"
00595 " s - Skip playing the initial prompts.\n";
00596
00597
00598 static char *app = "VoiceMail";
00599
00600
00601 static char *app2 = "VoiceMailMain";
00602
00603 static char *app3 = "MailboxExists";
00604 static char *app4 = "VMAuthenticate";
00605
00606 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00607 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00608 static char zonetag[80];
00609 static int maxsilence;
00610 static int maxmsg;
00611 static int maxdeletedmsg;
00612 static int silencethreshold = 128;
00613 static char serveremail[80];
00614 static char mailcmd[160];
00615 static char externnotify[160];
00616 static struct ast_smdi_interface *smdi_iface = NULL;
00617 static char vmfmts[80];
00618 static double volgain;
00619 static int vmminsecs;
00620 static int vmmaxsecs;
00621 static int maxgreet;
00622 static int skipms;
00623 static int maxlogins;
00624 static int minpassword;
00625
00626
00627
00628 static unsigned int poll_mailboxes;
00629
00630
00631 static unsigned int poll_freq;
00632
00633 #define DEFAULT_POLL_FREQ 30
00634
00635 AST_MUTEX_DEFINE_STATIC(poll_lock);
00636 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00637 static pthread_t poll_thread = AST_PTHREADT_NULL;
00638 static unsigned char poll_thread_run;
00639
00640
00641 static struct ast_event_sub *mwi_sub_sub;
00642
00643 static struct ast_event_sub *mwi_unsub_sub;
00644
00645
00646
00647
00648
00649
00650
00651
00652 struct mwi_sub {
00653 AST_RWLIST_ENTRY(mwi_sub) entry;
00654 int old_urgent;
00655 int old_new;
00656 int old_old;
00657 uint32_t uniqueid;
00658 char mailbox[1];
00659 };
00660
00661 struct mwi_sub_task {
00662 const char *mailbox;
00663 const char *context;
00664 uint32_t uniqueid;
00665 };
00666
00667 static struct ast_taskprocessor *mwi_subscription_tps;
00668
00669 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00670
00671
00672 static char listen_control_forward_key[12];
00673 static char listen_control_reverse_key[12];
00674 static char listen_control_pause_key[12];
00675 static char listen_control_restart_key[12];
00676 static char listen_control_stop_key[12];
00677
00678
00679 static char vm_password[80] = "vm-password";
00680 static char vm_newpassword[80] = "vm-newpassword";
00681 static char vm_passchanged[80] = "vm-passchanged";
00682 static char vm_reenterpassword[80] = "vm-reenterpassword";
00683 static char vm_mismatch[80] = "vm-mismatch";
00684 static char vm_invalid_password[80] = "vm-invalid-password";
00685 static char vm_pls_try_again[80] = "vm-pls-try-again";
00686
00687 static struct ast_flags globalflags = {0};
00688
00689 static int saydurationminfo;
00690
00691 static char dialcontext[AST_MAX_CONTEXT] = "";
00692 static char callcontext[AST_MAX_CONTEXT] = "";
00693 static char exitcontext[AST_MAX_CONTEXT] = "";
00694
00695 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00696
00697
00698 static char *emailbody = NULL;
00699 static char *emailsubject = NULL;
00700 static char *pagerbody = NULL;
00701 static char *pagersubject = NULL;
00702 static char fromstring[100];
00703 static char pagerfromstring[100];
00704 static char charset[32] = "ISO-8859-1";
00705
00706 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00707 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00708 static int adsiver = 1;
00709 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00710
00711
00712 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00713 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);
00714 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00715 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00716 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
00717 signed char record_gain, struct vm_state *vms, char *flag);
00718 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00719 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00720 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag);
00721 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag);
00722 static void apply_options(struct ast_vm_user *vmu, const char *options);
00723 static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum);
00724 static int is_valid_dtmf(const char *key);
00725
00726 struct ao2_container *inprocess_container;
00727
00728 struct inprocess {
00729 int count;
00730 char *context;
00731 char mailbox[0];
00732 };
00733
00734 static int inprocess_hash_fn(const void *obj, const int flags)
00735 {
00736 const struct inprocess *i = obj;
00737 return atoi(i->mailbox);
00738 }
00739
00740 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00741 {
00742 struct inprocess *i = obj, *j = arg;
00743 if (!strcmp(i->mailbox, j->mailbox)) {
00744 return 0;
00745 }
00746 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00747 }
00748
00749 static int inprocess_count(const char *context, const char *mailbox, int delta)
00750 {
00751 struct inprocess *i, *arg = alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00752 arg->context = arg->mailbox + strlen(mailbox) + 1;
00753 strcpy(arg->mailbox, mailbox);
00754 strcpy(arg->context, context);
00755 ao2_lock(inprocess_container);
00756 if ((i = ao2_find(inprocess_container, arg, 0))) {
00757 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00758 ao2_unlock(inprocess_container);
00759 ao2_ref(i, -1);
00760 return ret;
00761 }
00762 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00763 ao2_unlock(inprocess_container);
00764 return 0;
00765 }
00766 i->context = i->mailbox + strlen(mailbox) + 1;
00767 strcpy(i->mailbox, mailbox);
00768 strcpy(i->context, context);
00769 i->count = delta;
00770 ao2_link(inprocess_container, i);
00771 ao2_unlock(inprocess_container);
00772 ao2_ref(i, -1);
00773 return 0;
00774 }
00775
00776 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00777 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00778 #endif
00779
00780
00781
00782
00783
00784
00785
00786 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00787 {
00788 char *bufptr = buf;
00789 for (; *input; input++) {
00790 if (*input < 32) {
00791 continue;
00792 }
00793 *bufptr++ = *input;
00794 if (bufptr == buf + buflen - 1) {
00795 break;
00796 }
00797 }
00798 *bufptr = '\0';
00799 return buf;
00800 }
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815 static void populate_defaults(struct ast_vm_user *vmu)
00816 {
00817 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
00818 if (saydurationminfo)
00819 vmu->saydurationm = saydurationminfo;
00820 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
00821 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
00822 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
00823 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
00824 if (vmmaxsecs)
00825 vmu->maxsecs = vmmaxsecs;
00826 if (maxmsg)
00827 vmu->maxmsg = maxmsg;
00828 if (maxdeletedmsg)
00829 vmu->maxdeletedmsg = maxdeletedmsg;
00830 vmu->volgain = volgain;
00831 }
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
00842 {
00843 int x;
00844 if (!strcasecmp(var, "attach")) {
00845 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
00846 } else if (!strcasecmp(var, "attachfmt")) {
00847 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
00848 } else if (!strcasecmp(var, "serveremail")) {
00849 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
00850 } else if (!strcasecmp(var, "language")) {
00851 ast_copy_string(vmu->language, value, sizeof(vmu->language));
00852 } else if (!strcasecmp(var, "tz")) {
00853 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
00854 #ifdef IMAP_STORAGE
00855 } else if (!strcasecmp(var, "imapuser")) {
00856 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
00857 vmu->imapversion = imapversion;
00858 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
00859 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
00860 vmu->imapversion = imapversion;
00861 } else if (!strcasecmp(var, "imapvmshareid")) {
00862 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
00863 vmu->imapversion = imapversion;
00864 #endif
00865 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
00866 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
00867 } else if (!strcasecmp(var, "saycid")){
00868 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
00869 } else if (!strcasecmp(var,"sendvoicemail")){
00870 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
00871 } else if (!strcasecmp(var, "review")){
00872 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
00873 } else if (!strcasecmp(var, "tempgreetwarn")){
00874 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
00875 } else if (!strcasecmp(var, "messagewrap")){
00876 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
00877 } else if (!strcasecmp(var, "operator")) {
00878 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
00879 } else if (!strcasecmp(var, "envelope")){
00880 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
00881 } else if (!strcasecmp(var, "moveheard")){
00882 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
00883 } else if (!strcasecmp(var, "sayduration")){
00884 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
00885 } else if (!strcasecmp(var, "saydurationm")){
00886 if (sscanf(value, "%30d", &x) == 1) {
00887 vmu->saydurationm = x;
00888 } else {
00889 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
00890 }
00891 } else if (!strcasecmp(var, "forcename")){
00892 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
00893 } else if (!strcasecmp(var, "forcegreetings")){
00894 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
00895 } else if (!strcasecmp(var, "callback")) {
00896 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
00897 } else if (!strcasecmp(var, "dialout")) {
00898 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
00899 } else if (!strcasecmp(var, "exitcontext")) {
00900 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
00901 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
00902 vmu->maxsecs = atoi(value);
00903 if (vmu->maxsecs <= 0) {
00904 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
00905 vmu->maxsecs = vmmaxsecs;
00906 } else {
00907 vmu->maxsecs = atoi(value);
00908 }
00909 if (!strcasecmp(var, "maxmessage"))
00910 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
00911 } else if (!strcasecmp(var, "maxmsg")) {
00912 vmu->maxmsg = atoi(value);
00913 if (vmu->maxmsg <= 0) {
00914 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
00915 vmu->maxmsg = MAXMSG;
00916 } else if (vmu->maxmsg > MAXMSGLIMIT) {
00917 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
00918 vmu->maxmsg = MAXMSGLIMIT;
00919 }
00920 } else if (!strcasecmp(var, "backupdeleted")) {
00921 if (sscanf(value, "%30d", &x) == 1)
00922 vmu->maxdeletedmsg = x;
00923 else if (ast_true(value))
00924 vmu->maxdeletedmsg = MAXMSG;
00925 else
00926 vmu->maxdeletedmsg = 0;
00927
00928 if (vmu->maxdeletedmsg < 0) {
00929 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
00930 vmu->maxdeletedmsg = MAXMSG;
00931 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
00932 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
00933 vmu->maxdeletedmsg = MAXMSGLIMIT;
00934 }
00935 } else if (!strcasecmp(var, "volgain")) {
00936 sscanf(value, "%30lf", &vmu->volgain);
00937 } else if (!strcasecmp(var, "options")) {
00938 apply_options(vmu, value);
00939 }
00940 }
00941
00942 static char *vm_check_password_shell(char *command, char *buf, size_t len)
00943 {
00944 int fds[2], pid = 0;
00945
00946 memset(buf, 0, len);
00947
00948 if (pipe(fds)) {
00949 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
00950 } else {
00951
00952 pid = ast_safe_fork(0);
00953
00954 if (pid < 0) {
00955
00956 close(fds[0]);
00957 close(fds[1]);
00958 snprintf(buf, len, "FAILURE: Fork failed");
00959 } else if (pid) {
00960
00961 close(fds[1]);
00962 if (read(fds[0], buf, len) < 0) {
00963 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
00964 }
00965 close(fds[0]);
00966 } else {
00967
00968 AST_DECLARE_APP_ARGS(arg,
00969 AST_APP_ARG(v)[20];
00970 );
00971 char *mycmd = ast_strdupa(command);
00972
00973 close(fds[0]);
00974 dup2(fds[1], STDOUT_FILENO);
00975 close(fds[1]);
00976 ast_close_fds_above_n(STDOUT_FILENO);
00977
00978 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
00979
00980 execv(arg.v[0], arg.v);
00981 printf("FAILURE: %s", strerror(errno));
00982 _exit(0);
00983 }
00984 }
00985 return buf;
00986 }
00987
00988
00989
00990
00991
00992
00993
00994
00995 static int check_password(struct ast_vm_user *vmu, char *password)
00996 {
00997
00998 if (strlen(password) < minpassword)
00999 return 1;
01000 if (!ast_strlen_zero(ext_pass_check_cmd)) {
01001 char cmd[255], buf[255];
01002
01003 ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
01004
01005 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01006 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01007 ast_debug(5, "Result: %s\n", buf);
01008 if (!strncasecmp(buf, "VALID", 5)) {
01009 ast_debug(3, "Passed password check: '%s'\n", buf);
01010 return 0;
01011 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01012 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01013 return 0;
01014 } else {
01015 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01016 return 1;
01017 }
01018 }
01019 }
01020 return 0;
01021 }
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01034 {
01035 int res = -1;
01036 if (!strcmp(vmu->password, password)) {
01037
01038 res = 0;
01039 } else if (!ast_strlen_zero(vmu->uniqueid)) {
01040 if (strlen(password) > 10) {
01041 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01042 }
01043 if (ast_update_realtime("voicemail", "uniqueid", vmu->uniqueid, "password", password, SENTINEL) > 0) {
01044 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01045 res = 0;
01046 }
01047 }
01048 return res;
01049 }
01050
01051
01052
01053
01054 static void apply_options(struct ast_vm_user *vmu, const char *options)
01055 {
01056 char *stringp;
01057 char *s;
01058 char *var, *value;
01059 stringp = ast_strdupa(options);
01060 while ((s = strsep(&stringp, "|"))) {
01061 value = s;
01062 if ((var = strsep(&value, "=")) && value) {
01063 apply_option(vmu, var, value);
01064 }
01065 }
01066 }
01067
01068
01069
01070
01071
01072
01073 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01074 {
01075 struct ast_variable *tmp;
01076 tmp = var;
01077 while (tmp) {
01078 if (!strcasecmp(tmp->name, "vmsecret")) {
01079 ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
01080 } else if (!strcasecmp(tmp->name, "secret") || !strcasecmp(tmp->name, "password")) {
01081 if (ast_strlen_zero(retval->password))
01082 ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
01083 } else if (!strcasecmp(tmp->name, "uniqueid")) {
01084 ast_copy_string(retval->uniqueid, tmp->value, sizeof(retval->uniqueid));
01085 } else if (!strcasecmp(tmp->name, "pager")) {
01086 ast_copy_string(retval->pager, tmp->value, sizeof(retval->pager));
01087 } else if (!strcasecmp(tmp->name, "email")) {
01088 ast_copy_string(retval->email, tmp->value, sizeof(retval->email));
01089 } else if (!strcasecmp(tmp->name, "fullname")) {
01090 ast_copy_string(retval->fullname, tmp->value, sizeof(retval->fullname));
01091 } else if (!strcasecmp(tmp->name, "context")) {
01092 ast_copy_string(retval->context, tmp->value, sizeof(retval->context));
01093 #ifdef IMAP_STORAGE
01094 } else if (!strcasecmp(tmp->name, "imapuser")) {
01095 ast_copy_string(retval->imapuser, tmp->value, sizeof(retval->imapuser));
01096 retval->imapversion = imapversion;
01097 } else if (!strcasecmp(tmp->name, "imappassword") || !strcasecmp(tmp->name, "imapsecret")) {
01098 ast_copy_string(retval->imappassword, tmp->value, sizeof(retval->imappassword));
01099 retval->imapversion = imapversion;
01100 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01101 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01102 retval->imapversion = imapversion;
01103 #endif
01104 } else
01105 apply_option(retval, tmp->name, tmp->value);
01106 tmp = tmp->next;
01107 }
01108 }
01109
01110
01111
01112
01113
01114
01115
01116
01117 static int is_valid_dtmf(const char *key)
01118 {
01119 int i;
01120 char *local_key = ast_strdupa(key);
01121
01122 for (i = 0; i < strlen(key); ++i) {
01123 if (!strchr(VALID_DTMF, *local_key)) {
01124 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01125 return 0;
01126 }
01127 local_key++;
01128 }
01129 return 1;
01130 }
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01143 {
01144 struct ast_variable *var;
01145 struct ast_vm_user *retval;
01146
01147 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01148 if (!ivm)
01149 ast_set_flag(retval, VM_ALLOCED);
01150 else
01151 memset(retval, 0, sizeof(*retval));
01152 if (mailbox)
01153 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01154 populate_defaults(retval);
01155 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
01156 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01157 else
01158 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01159 if (var) {
01160 apply_options_full(retval, var);
01161 ast_variables_destroy(var);
01162 } else {
01163 if (!ivm)
01164 ast_free(retval);
01165 retval = NULL;
01166 }
01167 }
01168 return retval;
01169 }
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01180 {
01181
01182 struct ast_vm_user *vmu=NULL, *cur;
01183 AST_LIST_LOCK(&users);
01184
01185 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01186 context = "default";
01187
01188 AST_LIST_TRAVERSE(&users, cur, list) {
01189 #ifdef IMAP_STORAGE
01190 if (cur->imapversion != imapversion) {
01191 continue;
01192 }
01193 #endif
01194 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01195 break;
01196 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01197 break;
01198 }
01199 if (cur) {
01200
01201 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01202 memcpy(vmu, cur, sizeof(*vmu));
01203 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01204 AST_LIST_NEXT(vmu, list) = NULL;
01205 }
01206 } else
01207 vmu = find_user_realtime(ivm, context, mailbox);
01208 AST_LIST_UNLOCK(&users);
01209 return vmu;
01210 }
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01223 {
01224
01225 struct ast_vm_user *cur;
01226 int res = -1;
01227 AST_LIST_LOCK(&users);
01228 AST_LIST_TRAVERSE(&users, cur, list) {
01229 if ((!context || !strcasecmp(context, cur->context)) &&
01230 (!strcasecmp(mailbox, cur->mailbox)))
01231 break;
01232 }
01233 if (cur) {
01234 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01235 res = 0;
01236 }
01237 AST_LIST_UNLOCK(&users);
01238 return res;
01239 }
01240
01241
01242
01243
01244
01245
01246
01247
01248 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01249 {
01250 struct ast_config *cfg=NULL;
01251 struct ast_variable *var=NULL;
01252 struct ast_category *cat=NULL;
01253 char *category=NULL, *value=NULL, *new=NULL;
01254 const char *tmp=NULL;
01255 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01256 if (!change_password_realtime(vmu, newpassword))
01257 return;
01258
01259
01260 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags))) {
01261 while ((category = ast_category_browse(cfg, category))) {
01262 if (!strcasecmp(category, vmu->context)) {
01263 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01264 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01265 break;
01266 }
01267 value = strstr(tmp,",");
01268 if (!value) {
01269 ast_log(AST_LOG_WARNING, "variable has bad format.\n");
01270 break;
01271 }
01272 new = alloca((strlen(value)+strlen(newpassword)+1));
01273 sprintf(new,"%s%s", newpassword, value);
01274 if (!(cat = ast_category_get(cfg, category))) {
01275 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01276 break;
01277 }
01278 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01279 }
01280 }
01281
01282 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01283 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01284 config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01285 }
01286 category = NULL;
01287 var = NULL;
01288
01289
01290 if ((cfg = ast_config_load("users.conf", config_flags))) {
01291 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01292 while ((category = ast_category_browse(cfg, category))) {
01293 ast_debug(4, "users.conf: %s\n", category);
01294 if (!strcasecmp(category, vmu->mailbox)) {
01295 if (!(tmp = ast_variable_retrieve(cfg, category, "vmsecret"))) {
01296 ast_debug(3, "looks like we need to make vmsecret!\n");
01297 var = ast_variable_new("vmsecret", newpassword, "");
01298 }
01299 new = alloca(strlen(newpassword)+1);
01300 sprintf(new, "%s", newpassword);
01301 if (!(cat = ast_category_get(cfg, category))) {
01302 ast_debug(4, "failed to get category!\n");
01303 break;
01304 }
01305 if (!var)
01306 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01307 else
01308 ast_variable_append(cat, var);
01309 }
01310 }
01311
01312 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01313 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01314 config_text_file_save("users.conf", cfg, "AppVoicemail");
01315 }
01316 }
01317
01318 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01319 {
01320 char buf[255];
01321 snprintf(buf,255,"%s %s %s %s",ext_pass_cmd,vmu->context,vmu->mailbox,newpassword);
01322 if (!ast_safe_system(buf)) {
01323 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01324
01325 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01326 }
01327 }
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01340 {
01341 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01342 }
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354 static int make_file(char *dest, const int len, const char *dir, const int num)
01355 {
01356 return snprintf(dest, len, "%s/msg%04d", dir, num);
01357 }
01358
01359
01360 static FILE *vm_mkftemp(char *template)
01361 {
01362 FILE *p = NULL;
01363 int pfd = mkstemp(template);
01364 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01365 if (pfd > -1) {
01366 p = fdopen(pfd, "w+");
01367 if (!p) {
01368 close(pfd);
01369 pfd = -1;
01370 }
01371 }
01372 return p;
01373 }
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01384 {
01385 mode_t mode = VOICEMAIL_DIR_MODE;
01386 int res;
01387
01388 make_dir(dest, len, context, ext, folder);
01389 if ((res = ast_mkdir(dest, mode))) {
01390 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01391 return -1;
01392 }
01393 return 0;
01394 }
01395
01396 static const char *mbox(int id)
01397 {
01398 static const char *msgs[] = {
01399 #ifdef IMAP_STORAGE
01400 imapfolder,
01401 #else
01402 "INBOX",
01403 #endif
01404 "Old",
01405 "Work",
01406 "Family",
01407 "Friends",
01408 "Cust1",
01409 "Cust2",
01410 "Cust3",
01411 "Cust4",
01412 "Cust5",
01413 "Deleted",
01414 "Urgent"
01415 };
01416 return (id >= 0 && id < (sizeof(msgs)/sizeof(msgs[0]))) ? msgs[id] : "Unknown";
01417 }
01418
01419 static void free_user(struct ast_vm_user *vmu)
01420 {
01421 if (ast_test_flag(vmu, VM_ALLOCED))
01422 ast_free(vmu);
01423 }
01424
01425
01426
01427 #ifdef IMAP_STORAGE
01428 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01429 {
01430 char arg[10];
01431 struct vm_state *vms;
01432 unsigned long messageNum;
01433
01434
01435 if (msgnum < 0 && !imapgreetings) {
01436 ast_filedelete(file, NULL);
01437 return;
01438 }
01439
01440 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01441 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);
01442 return;
01443 }
01444
01445
01446
01447 messageNum = vms->msgArray[msgnum];
01448 if (messageNum == 0) {
01449 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n",msgnum,messageNum);
01450 return;
01451 }
01452 if (option_debug > 2)
01453 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n",msgnum,messageNum);
01454
01455 snprintf (arg, sizeof(arg), "%lu",messageNum);
01456 ast_mutex_lock(&vms->lock);
01457 mail_setflag (vms->mailstream,arg,"\\DELETED");
01458 mail_expunge(vms->mailstream);
01459 ast_mutex_unlock(&vms->lock);
01460 }
01461
01462 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01463 {
01464 struct vm_state *vms_p;
01465 char *file, *filename;
01466 char *attachment;
01467 int ret = 0, i;
01468 BODY *body;
01469
01470
01471
01472
01473 if (msgnum > -1 || !imapgreetings) {
01474 return 0;
01475 } else {
01476 file = strrchr(ast_strdupa(dir), '/');
01477 if (file)
01478 *file++ = '\0';
01479 else {
01480 ast_debug (1, "Failed to procure file name from directory passed.\n");
01481 return -1;
01482 }
01483 }
01484
01485
01486 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01487 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01488
01489
01490
01491
01492 if (!(vms_p = create_vm_state_from_user(vmu))) {
01493 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01494 return -1;
01495 }
01496 }
01497
01498
01499 *vms_p->introfn = '\0';
01500
01501 ast_mutex_lock(&vms_p->lock);
01502 ret = init_mailstream(vms_p, GREETINGS_FOLDER);
01503 if (!vms_p->mailstream) {
01504 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01505 ast_mutex_unlock(&vms_p->lock);
01506 return -1;
01507 }
01508
01509
01510 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01511 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01512
01513 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01514 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01515 } else {
01516 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01517 ast_mutex_unlock(&vms_p->lock);
01518 return -1;
01519 }
01520 filename = strsep(&attachment, ".");
01521 if (!strcmp(filename, file)) {
01522 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01523 vms_p->msgArray[vms_p->curmsg] = i + 1;
01524 save_body(body, vms_p, "2", attachment, 0);
01525 ast_mutex_unlock(&vms_p->lock);
01526 return 0;
01527 }
01528 }
01529 ast_mutex_unlock(&vms_p->lock);
01530
01531 return -1;
01532 }
01533
01534 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01535 {
01536 BODY *body;
01537 char *header_content;
01538 char *attachedfilefmt;
01539 char buf[80];
01540 struct vm_state *vms;
01541 char text_file[PATH_MAX];
01542 FILE *text_file_ptr;
01543 int res = 0;
01544 struct ast_vm_user *vmu;
01545
01546 if (!(vmu = find_user(NULL, context, mailbox))) {
01547 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01548 return -1;
01549 }
01550
01551 if (msgnum < 0) {
01552 if (imapgreetings) {
01553 res = imap_retrieve_greeting(dir, msgnum, vmu);
01554 goto exit;
01555 } else {
01556 res = 0;
01557 goto exit;
01558 }
01559 }
01560
01561
01562
01563
01564 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01565
01566
01567
01568
01569
01570
01571
01572 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01573 res = -1;
01574 goto exit;
01575 }
01576
01577 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01578 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01579
01580
01581 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01582 res = 0;
01583 goto exit;
01584 }
01585
01586 if (option_debug > 2)
01587 ast_log (LOG_DEBUG,"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01588 if (vms->msgArray[msgnum] == 0) {
01589 ast_log (LOG_WARNING,"Trying to access unknown message\n");
01590 res = -1;
01591 goto exit;
01592 }
01593
01594
01595 ast_mutex_lock(&vms->lock);
01596 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01597 ast_mutex_unlock(&vms->lock);
01598
01599 if (ast_strlen_zero(header_content)) {
01600 ast_log (LOG_ERROR,"Could not fetch header for message number %ld\n",vms->msgArray[msgnum]);
01601 res = -1;
01602 goto exit;
01603 }
01604
01605 ast_mutex_lock(&vms->lock);
01606 mail_fetchstructure (vms->mailstream,vms->msgArray[msgnum],&body);
01607 ast_mutex_unlock(&vms->lock);
01608
01609
01610 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01611 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01612 } else {
01613 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01614 res = -1;
01615 goto exit;
01616 }
01617
01618
01619
01620 strsep(&attachedfilefmt, ".");
01621 if (!attachedfilefmt) {
01622 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01623 res = -1;
01624 goto exit;
01625 }
01626
01627 save_body(body, vms, "2", attachedfilefmt, 0);
01628 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
01629 *vms->introfn = '\0';
01630 }
01631
01632
01633 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01634
01635 if (!(text_file_ptr = fopen(text_file, "w"))) {
01636 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
01637 }
01638
01639 fprintf(text_file_ptr, "%s\n", "[message]");
01640
01641 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
01642 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
01643 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
01644 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
01645 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
01646 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
01647 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
01648 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
01649 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
01650 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
01651 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
01652 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
01653 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
01654 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
01655 fclose(text_file_ptr);
01656
01657 exit:
01658 free_user(vmu);
01659 return res;
01660 }
01661
01662 static int folder_int(const char *folder)
01663 {
01664
01665 if (!folder)
01666 return 0;
01667 #ifdef IMAP_STORAGE
01668 if (!strcasecmp(folder, imapfolder))
01669 #else
01670 if (!strcasecmp(folder, "INBOX"))
01671 #endif
01672 return 0;
01673 else if (!strcasecmp(folder, "Old"))
01674 return 1;
01675 else if (!strcasecmp(folder, "Work"))
01676 return 2;
01677 else if (!strcasecmp(folder, "Family"))
01678 return 3;
01679 else if (!strcasecmp(folder, "Friends"))
01680 return 4;
01681 else if (!strcasecmp(folder, "Cust1"))
01682 return 5;
01683 else if (!strcasecmp(folder, "Cust2"))
01684 return 6;
01685 else if (!strcasecmp(folder, "Cust3"))
01686 return 7;
01687 else if (!strcasecmp(folder, "Cust4"))
01688 return 8;
01689 else if (!strcasecmp(folder, "Cust5"))
01690 return 9;
01691 else
01692 return 0;
01693 }
01694
01695 static int __messagecount(const char *context, const char *mailbox, const char *folder)
01696 {
01697 SEARCHPGM *pgm;
01698 SEARCHHEADER *hdr;
01699
01700 struct ast_vm_user *vmu, vmus;
01701 struct vm_state *vms_p;
01702 int ret = 0;
01703 int fold = folder_int(folder);
01704 int urgent = 0;
01705
01706
01707 if (fold == 11) {
01708 fold = NEW_FOLDER;
01709 urgent = 1;
01710 }
01711
01712 if (ast_strlen_zero(mailbox))
01713 return 0;
01714
01715
01716 vmu = find_user(&vmus, context, mailbox);
01717 if (!vmu) {
01718 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
01719 return -1;
01720 } else {
01721
01722 if (vmu->imapuser[0] == '\0') {
01723 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
01724 return -1;
01725 }
01726 }
01727
01728
01729 if (vmu->imapuser[0] == '\0') {
01730 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
01731 free_user(vmu);
01732 return -1;
01733 }
01734
01735
01736 vms_p = get_vm_state_by_imapuser(vmu->imapuser,1);
01737 if (!vms_p) {
01738 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
01739 }
01740 if (vms_p) {
01741 ast_debug(3, "Returning before search - user is logged in\n");
01742 if (fold == 0) {
01743 return vms_p->newmessages;
01744 }
01745 if (fold == 1) {
01746 return vms_p->oldmessages;
01747 }
01748 if (fold == 11) {
01749 return vms_p->urgentmessages;
01750 }
01751 }
01752
01753
01754 vms_p = get_vm_state_by_imapuser(vmu->imapuser,0);
01755 if (!vms_p) {
01756 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
01757 }
01758
01759 if (!vms_p) {
01760 vms_p = create_vm_state_from_user(vmu);
01761 }
01762 ret = init_mailstream(vms_p, fold);
01763 if (!vms_p->mailstream) {
01764 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
01765 return -1;
01766 }
01767 if (ret == 0) {
01768 ast_mutex_lock(&vms_p->lock);
01769 pgm = mail_newsearchpgm ();
01770 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
01771 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
01772 pgm->header = hdr;
01773 if (fold != 1) {
01774 pgm->unseen = 1;
01775 pgm->seen = 0;
01776 }
01777
01778
01779
01780 else {
01781 pgm->unseen = 0;
01782 pgm->seen = 1;
01783 }
01784
01785 if (urgent) {
01786 pgm->flagged = 1;
01787 pgm->unflagged = 0;
01788 }
01789 pgm->undeleted = 1;
01790 pgm->deleted = 0;
01791
01792 vms_p->vmArrayIndex = 0;
01793 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
01794 if (fold == 0 && urgent == 0)
01795 vms_p->newmessages = vms_p->vmArrayIndex;
01796 if (fold == 1)
01797 vms_p->oldmessages = vms_p->vmArrayIndex;
01798 if (fold == 0 && urgent == 1)
01799 vms_p->urgentmessages = vms_p->vmArrayIndex;
01800
01801 mail_free_searchpgm(&pgm);
01802 ast_mutex_unlock(&vms_p->lock);
01803 vms_p->updated = 0;
01804 return vms_p->vmArrayIndex;
01805 } else {
01806 ast_mutex_lock(&vms_p->lock);
01807 mail_ping(vms_p->mailstream);
01808 ast_mutex_unlock(&vms_p->lock);
01809 }
01810 return 0;
01811 }
01812
01813 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
01814 {
01815
01816 check_quota(vms, imapfolder);
01817 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
01818 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
01819 ast_play_and_wait(chan, "vm-mailboxfull");
01820 return -1;
01821 }
01822
01823
01824 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, 0)) {
01825 ast_log(AST_LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u > %u)\n", msgnum, vmu->maxmsg);
01826 ast_play_and_wait(chan, "vm-mailboxfull");
01827 return -1;
01828 }
01829
01830 return 0;
01831 }
01832
01833
01834
01835
01836
01837
01838
01839
01840
01841
01842 static int messagecount(const char *context, const char *mailbox, const char *folder)
01843 {
01844 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
01845 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
01846 } else {
01847 return __messagecount(context, mailbox, folder);
01848 }
01849 }
01850
01851 static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag)
01852 {
01853 char *myserveremail = serveremail;
01854 char fn[PATH_MAX];
01855 char introfn[PATH_MAX];
01856 char mailbox[256];
01857 char *stringp;
01858 FILE *p=NULL;
01859 char tmp[80] = "/tmp/astmail-XXXXXX";
01860 long len;
01861 void *buf;
01862 int tempcopy = 0;
01863 STRING str;
01864 int ret;
01865 char *imap_flags = NIL;
01866 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
01867
01868
01869 if (msgnum < 0 && !imapgreetings) {
01870 return 0;
01871 }
01872
01873 if (imap_check_limits(chan, vms, vmu, msgcount)) {
01874 return -1;
01875 }
01876
01877
01878 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
01879 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
01880 imap_flags="\\FLAGGED";
01881 }
01882
01883
01884 fmt = ast_strdupa(fmt);
01885 stringp = fmt;
01886 strsep(&stringp, "|");
01887
01888 if (!ast_strlen_zero(vmu->serveremail))
01889 myserveremail = vmu->serveremail;
01890
01891 if (msgnum > -1)
01892 make_file(fn, sizeof(fn), dir, msgnum);
01893 else
01894 ast_copy_string (fn, dir, sizeof(fn));
01895
01896 snprintf(introfn, sizeof(introfn), "%sintro", fn);
01897 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
01898 *introfn = '\0';
01899 }
01900
01901 if (ast_strlen_zero(vmu->email)) {
01902
01903
01904
01905
01906
01907 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
01908 tempcopy = 1;
01909 }
01910
01911 if (!strcmp(fmt, "wav49"))
01912 fmt = "WAV";
01913 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
01914
01915
01916
01917 if (!(p = vm_mkftemp(tmp))) {
01918 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
01919 if (tempcopy)
01920 *(vmu->email) = '\0';
01921 return -1;
01922 }
01923
01924 if (msgnum < 0 && imapgreetings) {
01925 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
01926 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
01927 return -1;
01928 }
01929 imap_delete_old_greeting(fn, vms);
01930 }
01931
01932 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX", S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
01933
01934 len = ftell(p);
01935 rewind(p);
01936 if (!(buf = ast_malloc(len + 1))) {
01937 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
01938 fclose(p);
01939 if (tempcopy)
01940 *(vmu->email) = '\0';
01941 return -1;
01942 }
01943 if (fread(buf, len, 1, p) < len) {
01944 if (ferror(p)) {
01945 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
01946 return -1;
01947 }
01948 }
01949 ((char *)buf)[len] = '\0';
01950 INIT(&str, mail_string, buf, len);
01951 ret = init_mailstream(vms, NEW_FOLDER);
01952 if (ret == 0) {
01953 imap_mailbox_name(mailbox, sizeof(mailbox), vms, NEW_FOLDER, 1);
01954 ast_mutex_lock(&vms->lock);
01955 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
01956 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
01957 ast_mutex_unlock(&vms->lock);
01958 fclose(p);
01959 unlink(tmp);
01960 ast_free(buf);
01961 } else {
01962 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n",mailbox);
01963 fclose(p);
01964 unlink(tmp);
01965 ast_free(buf);
01966 return -1;
01967 }
01968 ast_debug(3, "%s stored\n", fn);
01969
01970 if (tempcopy)
01971 *(vmu->email) = '\0';
01972
01973 return 0;
01974
01975 }
01976
01977
01978
01979
01980
01981
01982
01983
01984
01985
01986
01987
01988
01989
01990 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
01991 {
01992 char tmp[PATH_MAX] = "";
01993 char *mailboxnc;
01994 char *context;
01995 char *mb;
01996 char *cur;
01997 if (newmsgs)
01998 *newmsgs = 0;
01999 if (oldmsgs)
02000 *oldmsgs = 0;
02001 if (urgentmsgs)
02002 *urgentmsgs = 0;
02003
02004 ast_debug(3,"Mailbox is set to %s\n",mailbox_context);
02005
02006 if (ast_strlen_zero(mailbox_context))
02007 return 0;
02008
02009 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02010 context = strchr(tmp, '@');
02011 if (strchr(mailbox_context, ',')) {
02012 int tmpnew, tmpold, tmpurgent;
02013 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02014 mb = tmp;
02015 while ((cur = strsep(&mb, ", "))) {
02016 if (!ast_strlen_zero(cur)) {
02017 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02018 return -1;
02019 else {
02020 if (newmsgs)
02021 *newmsgs += tmpnew;
02022 if (oldmsgs)
02023 *oldmsgs += tmpold;
02024 if (urgentmsgs)
02025 *urgentmsgs += tmpurgent;
02026 }
02027 }
02028 }
02029 return 0;
02030 }
02031 if (context) {
02032 *context = '\0';
02033 mailboxnc = tmp;
02034 context++;
02035 } else {
02036 context = "default";
02037 mailboxnc = (char *)mailbox_context;
02038 }
02039 if (newmsgs) {
02040 if ((*newmsgs = __messagecount(context, mailboxnc, imapfolder)) < 0) {
02041 return -1;
02042 }
02043 }
02044 if (oldmsgs) {
02045 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02046 return -1;
02047 }
02048 }
02049 if (urgentmsgs) {
02050 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02051 return -1;
02052 }
02053 }
02054 return 0;
02055 }
02056
02057
02058
02059
02060
02061
02062
02063
02064
02065
02066
02067 static int has_voicemail(const char *mailbox, const char *folder)
02068 {
02069 char tmp[256], *tmp2, *box, *context;
02070 ast_copy_string(tmp, mailbox, sizeof(tmp));
02071 tmp2 = tmp;
02072 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02073 while ((box = strsep(&tmp2, ",&"))) {
02074 if (!ast_strlen_zero(box)) {
02075 if (has_voicemail(box, folder)) {
02076 return 1;
02077 }
02078 }
02079 }
02080 }
02081 if ((context = strchr(tmp, '@'))) {
02082 *context++ = '\0';
02083 } else {
02084 context = "default";
02085 }
02086 return __messagecount(context, tmp, folder) ? 1 : 0;
02087 }
02088
02089
02090
02091
02092
02093
02094
02095
02096
02097
02098
02099
02100
02101
02102
02103
02104 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, char *flag)
02105 {
02106 struct vm_state *sendvms = NULL, *destvms = NULL;
02107 char messagestring[10];
02108 if (msgnum >= recip->maxmsg) {
02109 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02110 return -1;
02111 }
02112 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02113 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02114 return -1;
02115 }
02116 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02117 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02118 return -1;
02119 }
02120 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02121 ast_mutex_lock(&sendvms->lock);
02122 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(imbox)) == T)) {
02123 ast_mutex_unlock(&sendvms->lock);
02124 return 0;
02125 }
02126 ast_mutex_unlock(&sendvms->lock);
02127 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02128 return -1;
02129 }
02130
02131 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02132 {
02133 char tmp[256], *t = tmp;
02134 size_t left = sizeof(tmp);
02135
02136 if (box == OLD_FOLDER) {
02137 ast_copy_string(vms->curbox, mbox(NEW_FOLDER), sizeof(vms->curbox));
02138 } else {
02139 ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
02140 }
02141
02142 if (box == NEW_FOLDER) {
02143 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02144 } else {
02145 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(box));
02146 }
02147
02148
02149 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02150
02151
02152 if (!ast_strlen_zero(authuser))
02153 ast_build_string(&t, &left, "/authuser=%s", authuser);
02154
02155
02156 if (!ast_strlen_zero(imapflags))
02157 ast_build_string(&t, &left, "/%s", imapflags);
02158
02159
02160 #if 1
02161 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02162 #else
02163 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02164 #endif
02165 if (box == NEW_FOLDER || box == OLD_FOLDER)
02166 snprintf(spec, len, "%s%s", tmp, use_folder? imapfolder: "INBOX");
02167 else if (box == GREETINGS_FOLDER)
02168 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02169 else {
02170 if (!ast_strlen_zero(imapparentfolder)) {
02171
02172 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(box));
02173 } else {
02174 snprintf(spec, len, "%s%s", tmp, mbox(box));
02175 }
02176 }
02177 }
02178
02179 static int init_mailstream(struct vm_state *vms, int box)
02180 {
02181 MAILSTREAM *stream = NIL;
02182 long debug;
02183 char tmp[256];
02184
02185 if (!vms) {
02186 ast_log (LOG_ERROR,"vm_state is NULL!\n");
02187 return -1;
02188 }
02189 if (option_debug > 2)
02190 ast_log (LOG_DEBUG,"vm_state user is:%s\n",vms->imapuser);
02191 if (vms->mailstream == NIL || !vms->mailstream) {
02192 if (option_debug)
02193 ast_log (LOG_DEBUG,"mailstream not set.\n");
02194 } else {
02195 stream = vms->mailstream;
02196 }
02197
02198 debug = NIL;
02199
02200 if (delimiter == '\0') {
02201 char *cp;
02202 #ifdef USE_SYSTEM_IMAP
02203 #include <imap/linkage.c>
02204 #elif defined(USE_SYSTEM_CCLIENT)
02205 #include <c-client/linkage.c>
02206 #else
02207 #include "linkage.c"
02208 #endif
02209
02210 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02211 ast_mutex_lock(&vms->lock);
02212 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02213 ast_mutex_unlock(&vms->lock);
02214 if (stream == NIL) {
02215 ast_log (LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02216 return -1;
02217 }
02218 get_mailbox_delimiter(stream);
02219
02220 for (cp = imapfolder; *cp; cp++)
02221 if (*cp == '/')
02222 *cp = delimiter;
02223 }
02224
02225 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02226 if (option_debug > 2)
02227 ast_log (LOG_DEBUG,"Before mail_open, server: %s, box:%d\n", tmp, box);
02228 ast_mutex_lock(&vms->lock);
02229 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02230 ast_mutex_unlock(&vms->lock);
02231 if (vms->mailstream == NIL) {
02232 return -1;
02233 } else {
02234 return 0;
02235 }
02236 }
02237
02238 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02239 {
02240 SEARCHPGM *pgm;
02241 SEARCHHEADER *hdr;
02242 int ret, urgent = 0;
02243
02244
02245 if (box == 11) {
02246 box = NEW_FOLDER;
02247 urgent = 1;
02248 }
02249
02250 ast_copy_string(vms->imapuser,vmu->imapuser, sizeof(vms->imapuser));
02251 ast_debug(3,"Before init_mailstream, user is %s\n",vmu->imapuser);
02252 vms->imapversion = vmu->imapversion;
02253
02254 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02255 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02256 return -1;
02257 }
02258
02259 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02260
02261
02262 if (box == 0) {
02263 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(box));
02264 check_quota(vms,(char *)mbox(box));
02265 }
02266
02267 ast_mutex_lock(&vms->lock);
02268 pgm = mail_newsearchpgm();
02269
02270
02271 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02272 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02273 pgm->header = hdr;
02274 pgm->deleted = 0;
02275 pgm->undeleted = 1;
02276
02277
02278 if (box == NEW_FOLDER && urgent == 1) {
02279 pgm->unseen = 1;
02280 pgm->seen = 0;
02281 pgm->flagged = 1;
02282 pgm->unflagged = 0;
02283 } else if (box == NEW_FOLDER && urgent == 0) {
02284 pgm->unseen = 1;
02285 pgm->seen = 0;
02286 pgm->flagged = 0;
02287 pgm->unflagged = 1;
02288 } else if (box == OLD_FOLDER) {
02289 pgm->seen = 1;
02290 pgm->unseen = 0;
02291 }
02292
02293 ast_debug(3,"Before mail_search_full, user is %s\n",vmu->imapuser);
02294
02295 vms->vmArrayIndex = 0;
02296 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02297 vms->lastmsg = vms->vmArrayIndex - 1;
02298 mail_free_searchpgm(&pgm);
02299
02300 ast_mutex_unlock(&vms->lock);
02301 return 0;
02302 }
02303
02304 static void write_file(char *filename, char *buffer, unsigned long len)
02305 {
02306 FILE *output;
02307
02308 output = fopen (filename, "w");
02309 if (fwrite(buffer, len, 1, output) != 1) {
02310 if (ferror(output)) {
02311 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02312 }
02313 }
02314 fclose (output);
02315 }
02316
02317 static void update_messages_by_imapuser(const char *user, unsigned long number)
02318 {
02319 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02320
02321 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02322 return;
02323 }
02324
02325 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02326 vms->msgArray[vms->vmArrayIndex++] = number;
02327 }
02328
02329 void mm_searched(MAILSTREAM *stream, unsigned long number)
02330 {
02331 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02332
02333 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02334 return;
02335
02336 update_messages_by_imapuser(user, number);
02337 }
02338
02339 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02340 {
02341 struct ast_variable *var;
02342 struct ast_vm_user *vmu;
02343
02344 vmu = ast_calloc(1, sizeof *vmu);
02345 if (!vmu)
02346 return NULL;
02347 ast_set_flag(vmu, VM_ALLOCED);
02348 populate_defaults(vmu);
02349
02350 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02351 if (var) {
02352 apply_options_full(vmu, var);
02353 ast_variables_destroy(var);
02354 return vmu;
02355 } else {
02356 ast_free(vmu);
02357 return NULL;
02358 }
02359 }
02360
02361
02362
02363 void mm_exists(MAILSTREAM * stream, unsigned long number)
02364 {
02365
02366 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02367 if (number == 0) return;
02368 set_update(stream);
02369 }
02370
02371
02372 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02373 {
02374
02375 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02376 if (number == 0) return;
02377 set_update(stream);
02378 }
02379
02380
02381 void mm_flags(MAILSTREAM * stream, unsigned long number)
02382 {
02383
02384 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02385 if (number == 0) return;
02386 set_update(stream);
02387 }
02388
02389
02390 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02391 {
02392 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02393 mm_log (string, errflg);
02394 }
02395
02396
02397 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02398 {
02399 if (delimiter == '\0') {
02400 delimiter = delim;
02401 }
02402
02403 ast_debug(5, "Delimiter set to %c and mailbox %s\n",delim, mailbox);
02404 if (attributes & LATT_NOINFERIORS)
02405 ast_debug(5, "no inferiors\n");
02406 if (attributes & LATT_NOSELECT)
02407 ast_debug(5, "no select\n");
02408 if (attributes & LATT_MARKED)
02409 ast_debug(5, "marked\n");
02410 if (attributes & LATT_UNMARKED)
02411 ast_debug(5, "unmarked\n");
02412 }
02413
02414
02415 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02416 {
02417 ast_debug(5, "Delimiter set to %c and mailbox %s\n",delim, mailbox);
02418 if (attributes & LATT_NOINFERIORS)
02419 ast_debug(5, "no inferiors\n");
02420 if (attributes & LATT_NOSELECT)
02421 ast_debug(5, "no select\n");
02422 if (attributes & LATT_MARKED)
02423 ast_debug(5, "marked\n");
02424 if (attributes & LATT_UNMARKED)
02425 ast_debug(5, "unmarked\n");
02426 }
02427
02428
02429 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02430 {
02431 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02432 if (status->flags & SA_MESSAGES)
02433 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02434 if (status->flags & SA_RECENT)
02435 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02436 if (status->flags & SA_UNSEEN)
02437 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02438 if (status->flags & SA_UIDVALIDITY)
02439 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02440 if (status->flags & SA_UIDNEXT)
02441 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02442 ast_log(AST_LOG_NOTICE, "\n");
02443 }
02444
02445
02446 void mm_log(char *string, long errflg)
02447 {
02448 switch ((short) errflg) {
02449 case NIL:
02450 ast_debug(1,"IMAP Info: %s\n", string);
02451 break;
02452 case PARSE:
02453 case WARN:
02454 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02455 break;
02456 case ERROR:
02457 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02458 break;
02459 }
02460 }
02461
02462
02463 void mm_dlog(char *string)
02464 {
02465 ast_log(AST_LOG_NOTICE, "%s\n", string);
02466 }
02467
02468
02469 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02470 {
02471 struct ast_vm_user *vmu;
02472
02473 ast_debug(4, "Entering callback mm_login\n");
02474
02475 ast_copy_string(user, mb->user, MAILTMPLEN);
02476
02477
02478 if (!ast_strlen_zero(authpassword)) {
02479 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02480 } else {
02481 AST_LIST_TRAVERSE(&users, vmu, list) {
02482 if (!strcasecmp(mb->user, vmu->imapuser)) {
02483 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02484 break;
02485 }
02486 }
02487 if (!vmu) {
02488 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02489 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02490 free_user(vmu);
02491 }
02492 }
02493 }
02494 }
02495
02496
02497 void mm_critical(MAILSTREAM * stream)
02498 {
02499 }
02500
02501
02502 void mm_nocritical(MAILSTREAM * stream)
02503 {
02504 }
02505
02506
02507 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02508 {
02509 kill (getpid (), SIGSTOP);
02510 return NIL;
02511 }
02512
02513
02514 void mm_fatal(char *string)
02515 {
02516 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02517 }
02518
02519
02520 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02521 {
02522 struct vm_state *vms;
02523 char *mailbox = stream->mailbox, *user;
02524 char buf[1024] = "";
02525 unsigned long usage = 0, limit = 0;
02526
02527 while (pquota) {
02528 usage = pquota->usage;
02529 limit = pquota->limit;
02530 pquota = pquota->next;
02531 }
02532
02533 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || (!(vms = get_vm_state_by_imapuser(user, 2)) && !(vms = get_vm_state_by_imapuser(user, 0)))) {
02534 ast_log(AST_LOG_ERROR, "No state found.\n");
02535 return;
02536 }
02537
02538 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02539
02540 vms->quota_usage = usage;
02541 vms->quota_limit = limit;
02542 }
02543
02544 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02545 {
02546 char *start, *eol_pnt;
02547 int taglen;
02548
02549 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02550 return NULL;
02551
02552 taglen = strlen(tag) + 1;
02553 if (taglen < 1)
02554 return NULL;
02555
02556 if (!(start = strstr(header, tag)))
02557 return NULL;
02558
02559
02560 memset(buf, 0, len);
02561
02562 ast_copy_string(buf, start+taglen, len);
02563 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02564 *eol_pnt = '\0';
02565 return buf;
02566 }
02567
02568 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02569 {
02570 char *start, *quote, *eol_pnt;
02571
02572 if (ast_strlen_zero(mailbox))
02573 return NULL;
02574
02575 if (!(start = strstr(mailbox, "/user=")))
02576 return NULL;
02577
02578 ast_copy_string(buf, start+6, len);
02579
02580 if (!(quote = strchr(buf, '\"'))) {
02581 if (!(eol_pnt = strchr(buf, '/')))
02582 eol_pnt = strchr(buf,'}');
02583 *eol_pnt = '\0';
02584 return buf;
02585 } else {
02586 eol_pnt = strchr(buf+1,'\"');
02587 *eol_pnt = '\0';
02588 return buf+1;
02589 }
02590 }
02591
02592 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02593 {
02594 struct vm_state *vms_p;
02595
02596 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02597 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
02598 return vms_p;
02599 }
02600 if (option_debug > 4)
02601 ast_log(AST_LOG_DEBUG,"Adding new vmstate for %s\n",vmu->imapuser);
02602 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
02603 return NULL;
02604 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
02605 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
02606 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
02607 vms_p->mailstream = NIL;
02608 vms_p->imapversion = vmu->imapversion;
02609 if (option_debug > 4)
02610 ast_log(AST_LOG_DEBUG,"Copied %s to %s\n",vmu->imapuser,vms_p->imapuser);
02611 vms_p->updated = 1;
02612
02613 ast_copy_string(vms_p->curbox, mbox(0), sizeof(vms_p->curbox));
02614 init_vm_state(vms_p);
02615 vmstate_insert(vms_p);
02616 return vms_p;
02617 }
02618
02619 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
02620 {
02621 struct vmstate *vlist = NULL;
02622
02623 if (interactive) {
02624 struct vm_state *vms;
02625 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02626 vms = pthread_getspecific(ts_vmstate.key);
02627 return vms;
02628 }
02629
02630 AST_LIST_LOCK(&vmstates);
02631 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
02632 if (!vlist->vms) {
02633 ast_debug(3, "error: vms is NULL for %s\n", user);
02634 continue;
02635 }
02636 if (vlist->vms->imapversion != imapversion) {
02637 continue;
02638 }
02639 if (!vlist->vms->imapuser) {
02640 ast_debug(3, "error: imapuser is NULL for %s\n", user);
02641 continue;
02642 }
02643
02644 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
02645 AST_LIST_UNLOCK(&vmstates);
02646 return vlist->vms;
02647 }
02648 }
02649 AST_LIST_UNLOCK(&vmstates);
02650
02651 ast_debug(3, "%s not found in vmstates\n", user);
02652
02653 return NULL;
02654 }
02655
02656 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
02657 {
02658
02659 struct vmstate *vlist = NULL;
02660 const char *local_context = S_OR(context, "default");
02661
02662 if (interactive) {
02663 struct vm_state *vms;
02664 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02665 vms = pthread_getspecific(ts_vmstate.key);
02666 return vms;
02667 }
02668
02669 AST_LIST_LOCK(&vmstates);
02670 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
02671 if (!vlist->vms) {
02672 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
02673 continue;
02674 }
02675 if (vlist->vms->imapversion != imapversion) {
02676 continue;
02677 }
02678 if (!vlist->vms->username || !vlist->vms->context) {
02679 ast_debug(3, "error: username is NULL for %s\n", mailbox);
02680 continue;
02681 }
02682
02683 ast_debug(3, "comparing mailbox %s@%s (i=%d) to vmstate mailbox %s@%s (i=%d)\n", mailbox, local_context, interactive, vlist->vms->username, vlist->vms->context, vlist->vms->interactive);
02684
02685 if (!strcmp(vlist->vms->username,mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
02686 ast_debug(3, "Found it!\n");
02687 AST_LIST_UNLOCK(&vmstates);
02688 return vlist->vms;
02689 }
02690 }
02691 AST_LIST_UNLOCK(&vmstates);
02692
02693 ast_debug(3, "%s not found in vmstates\n", mailbox);
02694
02695 return NULL;
02696 }
02697
02698 static void vmstate_insert(struct vm_state *vms)
02699 {
02700 struct vmstate *v;
02701 struct vm_state *altvms;
02702
02703
02704
02705
02706 if (vms->interactive == 1) {
02707 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
02708 if (altvms) {
02709 ast_debug(3, "Duplicate mailbox %s, copying message info...\n",vms->username);
02710 vms->newmessages = altvms->newmessages;
02711 vms->oldmessages = altvms->oldmessages;
02712 vms->vmArrayIndex = altvms->vmArrayIndex;
02713 vms->lastmsg = altvms->lastmsg;
02714 vms->curmsg = altvms->curmsg;
02715
02716 vms->persist_vms = altvms;
02717
02718 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
02719 vms->mailstream = altvms->mailstream;
02720 #else
02721 vms->mailstream = NIL;
02722 #endif
02723 }
02724 return;
02725 }
02726
02727 if (!(v = ast_calloc(1, sizeof(*v))))
02728 return;
02729
02730 v->vms = vms;
02731
02732 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n",vms->imapuser,vms->username);
02733
02734 AST_LIST_LOCK(&vmstates);
02735 AST_LIST_INSERT_TAIL(&vmstates, v, list);
02736 AST_LIST_UNLOCK(&vmstates);
02737 }
02738
02739 static void vmstate_delete(struct vm_state *vms)
02740 {
02741 struct vmstate *vc = NULL;
02742 struct vm_state *altvms = NULL;
02743
02744
02745
02746 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
02747 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
02748 altvms->newmessages = vms->newmessages;
02749 altvms->oldmessages = vms->oldmessages;
02750 altvms->updated = 1;
02751 vms->mailstream = mail_close(vms->mailstream);
02752
02753
02754 return;
02755 }
02756
02757 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
02758
02759 AST_LIST_LOCK(&vmstates);
02760 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
02761 if (vc->vms == vms) {
02762 AST_LIST_REMOVE_CURRENT(list);
02763 break;
02764 }
02765 }
02766 AST_LIST_TRAVERSE_SAFE_END
02767 AST_LIST_UNLOCK(&vmstates);
02768
02769 if (vc) {
02770 ast_mutex_destroy(&vc->vms->lock);
02771 ast_free(vc);
02772 }
02773 else
02774 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
02775 }
02776
02777 static void set_update(MAILSTREAM * stream)
02778 {
02779 struct vm_state *vms;
02780 char *mailbox = stream->mailbox, *user;
02781 char buf[1024] = "";
02782
02783 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
02784 if (user && option_debug > 2)
02785 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
02786 return;
02787 }
02788
02789 ast_debug(3, "User %s mailbox set for update.\n", user);
02790
02791 vms->updated = 1;
02792 }
02793
02794 static void init_vm_state(struct vm_state *vms)
02795 {
02796 int x;
02797 vms->vmArrayIndex = 0;
02798 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
02799 vms->msgArray[x] = 0;
02800 }
02801 ast_mutex_init(&vms->lock);
02802 }
02803
02804 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
02805 {
02806 char *body_content;
02807 char *body_decoded;
02808 char *fn = is_intro ? vms->introfn : vms->fn;
02809 unsigned long len;
02810 unsigned long newlen;
02811 char filename[256];
02812
02813 if (!body || body == NIL)
02814 return -1;
02815
02816 ast_mutex_lock(&vms->lock);
02817 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
02818 ast_mutex_unlock(&vms->lock);
02819 if (body_content != NIL) {
02820 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
02821
02822 body_decoded = rfc822_base64((unsigned char *)body_content, len, &newlen);
02823
02824 if (!newlen) {
02825 return -1;
02826 }
02827 write_file(filename, (char *) body_decoded, newlen);
02828 } else {
02829 ast_debug(5, "Body of message is NULL.\n");
02830 return -1;
02831 }
02832 return 0;
02833 }
02834
02835
02836
02837
02838
02839
02840
02841
02842 static void get_mailbox_delimiter(MAILSTREAM *stream) {
02843 char tmp[50];
02844 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
02845 mail_list(stream, tmp, "*");
02846 }
02847
02848
02849
02850
02851
02852
02853
02854
02855 static void check_quota(struct vm_state *vms, char *mailbox) {
02856 ast_mutex_lock(&vms->lock);
02857 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
02858 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
02859 if (vms && vms->mailstream != NULL) {
02860 imap_getquotaroot(vms->mailstream, mailbox);
02861 } else {
02862 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
02863 }
02864 ast_mutex_unlock(&vms->lock);
02865 }
02866
02867 #endif
02868
02869
02870
02871
02872
02873 static int vm_lock_path(const char *path)
02874 {
02875 switch (ast_lock_path(path)) {
02876 case AST_LOCK_TIMEOUT:
02877 return -1;
02878 default:
02879 return 0;
02880 }
02881 }
02882
02883
02884 #ifdef ODBC_STORAGE
02885 struct generic_prepare_struct {
02886 char *sql;
02887 int argc;
02888 char **argv;
02889 };
02890
02891 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
02892 {
02893 struct generic_prepare_struct *gps = data;
02894 int res, i;
02895 SQLHSTMT stmt;
02896
02897 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
02898 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02899 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
02900 return NULL;
02901 }
02902 res = SQLPrepare(stmt, (unsigned char *)gps->sql, SQL_NTS);
02903 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02904 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
02905 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
02906 return NULL;
02907 }
02908 for (i = 0; i < gps->argc; i++)
02909 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
02910
02911 return stmt;
02912 }
02913
02914
02915
02916
02917
02918
02919
02920
02921
02922
02923
02924
02925
02926
02927
02928 static int retrieve_file(char *dir, int msgnum)
02929 {
02930 int x = 0;
02931 int res;
02932 int fd=-1;
02933 size_t fdlen = 0;
02934 void *fdm = MAP_FAILED;
02935 SQLSMALLINT colcount=0;
02936 SQLHSTMT stmt;
02937 char sql[PATH_MAX];
02938 char fmt[80]="";
02939 char *c;
02940 char coltitle[256];
02941 SQLSMALLINT collen;
02942 SQLSMALLINT datatype;
02943 SQLSMALLINT decimaldigits;
02944 SQLSMALLINT nullable;
02945 SQLULEN colsize;
02946 SQLLEN colsize2;
02947 FILE *f=NULL;
02948 char rowdata[80];
02949 char fn[PATH_MAX];
02950 char full_fn[PATH_MAX];
02951 char msgnums[80];
02952 char *argv[] = { dir, msgnums };
02953 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
02954
02955 struct odbc_obj *obj;
02956 obj = ast_odbc_request_obj(odbc_database, 0);
02957 if (obj) {
02958 ast_copy_string(fmt, vmfmts, sizeof(fmt));
02959 c = strchr(fmt, '|');
02960 if (c)
02961 *c = '\0';
02962 if (!strcasecmp(fmt, "wav49"))
02963 strcpy(fmt, "WAV");
02964 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
02965 if (msgnum > -1)
02966 make_file(fn, sizeof(fn), dir, msgnum);
02967 else
02968 ast_copy_string(fn, dir, sizeof(fn));
02969
02970
02971 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
02972
02973 if (!(f = fopen(full_fn, "w+"))) {
02974 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
02975 goto yuck;
02976 }
02977
02978 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
02979 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?",odbc_table);
02980 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
02981 if (!stmt) {
02982 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
02983 ast_odbc_release_obj(obj);
02984 goto yuck;
02985 }
02986 res = SQLFetch(stmt);
02987 if (res == SQL_NO_DATA) {
02988 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02989 ast_odbc_release_obj(obj);
02990 goto yuck;
02991 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
02992 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
02993 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
02994 ast_odbc_release_obj(obj);
02995 goto yuck;
02996 }
02997 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
02998 if (fd < 0) {
02999 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03000 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03001 ast_odbc_release_obj(obj);
03002 goto yuck;
03003 }
03004 res = SQLNumResultCols(stmt, &colcount);
03005 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03006 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03007 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03008 ast_odbc_release_obj(obj);
03009 goto yuck;
03010 }
03011 if (f)
03012 fprintf(f, "[message]\n");
03013 for (x=0;x<colcount;x++) {
03014 rowdata[0] = '\0';
03015 collen = sizeof(coltitle);
03016 res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen,
03017 &datatype, &colsize, &decimaldigits, &nullable);
03018 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03019 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03020 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03021 ast_odbc_release_obj(obj);
03022 goto yuck;
03023 }
03024 if (!strcasecmp(coltitle, "recording")) {
03025 off_t offset;
03026 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03027 fdlen = colsize2;
03028 if (fd > -1) {
03029 char tmp[1]="";
03030 lseek(fd, fdlen - 1, SEEK_SET);
03031 if (write(fd, tmp, 1) != 1) {
03032 close(fd);
03033 fd = -1;
03034 continue;
03035 }
03036
03037 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03038 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03039 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03040 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03041 ast_odbc_release_obj(obj);
03042 goto yuck;
03043 } else {
03044 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03045 munmap(fdm, CHUNKSIZE);
03046 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03047 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03048 unlink(full_fn);
03049 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03050 ast_odbc_release_obj(obj);
03051 goto yuck;
03052 }
03053 }
03054 }
03055 if (truncate(full_fn, fdlen) < 0) {
03056 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03057 }
03058 }
03059 } else {
03060 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03061 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03062 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03063 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03064 ast_odbc_release_obj(obj);
03065 goto yuck;
03066 }
03067 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03068 fprintf(f, "%s=%s\n", coltitle, rowdata);
03069 }
03070 }
03071 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03072 ast_odbc_release_obj(obj);
03073 } else
03074 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03075 yuck:
03076 if (f)
03077 fclose(f);
03078 if (fd > -1)
03079 close(fd);
03080 return x - 1;
03081 }
03082
03083
03084
03085
03086
03087
03088
03089
03090
03091
03092
03093 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03094 {
03095 int x = 0;
03096 int res;
03097 SQLHSTMT stmt;
03098 char sql[PATH_MAX];
03099 char rowdata[20];
03100 char *argv[] = { dir };
03101 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03102
03103 struct odbc_obj *obj;
03104 obj = ast_odbc_request_obj(odbc_database, 0);
03105 if (obj) {
03106 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?",odbc_table);
03107 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03108 if (!stmt) {
03109 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03110 ast_odbc_release_obj(obj);
03111 goto yuck;
03112 }
03113 res = SQLFetch(stmt);
03114 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03115 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03116 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03117 ast_odbc_release_obj(obj);
03118 goto yuck;
03119 }
03120 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03121 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03122 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03123 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03124 ast_odbc_release_obj(obj);
03125 goto yuck;
03126 }
03127 if (sscanf(rowdata, "%30d", &x) != 1)
03128 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03129 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03130 ast_odbc_release_obj(obj);
03131 } else
03132 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03133 yuck:
03134 return x - 1;
03135 }
03136
03137
03138
03139
03140
03141
03142
03143
03144
03145
03146 static int message_exists(char *dir, int msgnum)
03147 {
03148 int x = 0;
03149 int res;
03150 SQLHSTMT stmt;
03151 char sql[PATH_MAX];
03152 char rowdata[20];
03153 char msgnums[20];
03154 char *argv[] = { dir, msgnums };
03155 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03156
03157 struct odbc_obj *obj;
03158 obj = ast_odbc_request_obj(odbc_database, 0);
03159 if (obj) {
03160 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03161 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?",odbc_table);
03162 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03163 if (!stmt) {
03164 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03165 ast_odbc_release_obj(obj);
03166 goto yuck;
03167 }
03168 res = SQLFetch(stmt);
03169 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03170 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03171 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03172 ast_odbc_release_obj(obj);
03173 goto yuck;
03174 }
03175 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03176 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03177 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03178 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03179 ast_odbc_release_obj(obj);
03180 goto yuck;
03181 }
03182 if (sscanf(rowdata, "%30d", &x) != 1)
03183 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03184 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03185 ast_odbc_release_obj(obj);
03186 } else
03187 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03188 yuck:
03189 return x;
03190 }
03191
03192
03193
03194
03195
03196
03197
03198
03199
03200
03201
03202
03203
03204 static int count_messages(struct ast_vm_user *vmu, char *dir)
03205 {
03206 return last_message_index(vmu, dir) + 1;
03207 }
03208
03209
03210
03211
03212
03213
03214
03215
03216
03217
03218
03219 static void delete_file(const char *sdir, int smsg)
03220 {
03221 SQLHSTMT stmt;
03222 char sql[PATH_MAX];
03223 char msgnums[20];
03224 char *argv[] = { NULL, msgnums };
03225 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03226 struct odbc_obj *obj;
03227
03228 argv[0] = ast_strdupa(sdir);
03229
03230 obj = ast_odbc_request_obj(odbc_database, 0);
03231 if (obj) {
03232 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03233 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?",odbc_table);
03234 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03235 if (!stmt)
03236 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03237 else
03238 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03239 ast_odbc_release_obj(obj);
03240 } else
03241 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03242 return;
03243 }
03244
03245
03246
03247
03248
03249
03250
03251
03252
03253
03254
03255
03256 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03257 {
03258 SQLHSTMT stmt;
03259 char sql[512];
03260 char msgnums[20];
03261 char msgnumd[20];
03262 struct odbc_obj *obj;
03263 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03264 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03265
03266 delete_file(ddir, dmsg);
03267 obj = ast_odbc_request_obj(odbc_database, 0);
03268 if (obj) {
03269 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03270 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03271 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, context, macrocontext, callerid, origtime, duration, recording, flag, mailboxuser, mailboxcontext) SELECT ?,?,context,macrocontext,callerid,origtime,duration,recording,flag,?,? FROM %s WHERE dir=? AND msgnum=?",odbc_table,odbc_table);
03272 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03273 if (!stmt)
03274 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03275 else
03276 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03277 ast_odbc_release_obj(obj);
03278 } else
03279 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03280 return;
03281 }
03282
03283 struct insert_data {
03284 char *sql;
03285 const char *dir;
03286 const char *msgnums;
03287 void *data;
03288 SQLLEN datalen;
03289 SQLLEN indlen;
03290 const char *context;
03291 const char *macrocontext;
03292 const char *callerid;
03293 const char *origtime;
03294 const char *duration;
03295 const char *mailboxuser;
03296 const char *mailboxcontext;
03297 const char *category;
03298 const char *flag;
03299 };
03300
03301 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03302 {
03303 struct insert_data *data = vdata;
03304 int res;
03305 SQLHSTMT stmt;
03306
03307 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03308 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03309 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03310 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03311 return NULL;
03312 }
03313
03314 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *)data->dir, 0, NULL);
03315 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *)data->msgnums, 0, NULL);
03316 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *)data->data, data->datalen, &data->indlen);
03317 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *)data->context, 0, NULL);
03318 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *)data->macrocontext, 0, NULL);
03319 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *)data->callerid, 0, NULL);
03320 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *)data->origtime, 0, NULL);
03321 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *)data->duration, 0, NULL);
03322 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *)data->mailboxuser, 0, NULL);
03323 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *)data->mailboxcontext, 0, NULL);
03324 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *)data->flag, 0, NULL);
03325 if (!ast_strlen_zero(data->category)) {
03326 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *)data->category, 0, NULL);
03327 }
03328 res = SQLExecDirect(stmt, (unsigned char *)data->sql, SQL_NTS);
03329 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03330 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03331 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03332 return NULL;
03333 }
03334
03335 return stmt;
03336 }
03337
03338
03339
03340
03341
03342
03343
03344
03345
03346
03347
03348
03349
03350
03351 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03352 {
03353 int res = 0;
03354 int fd = -1;
03355 void *fdm = MAP_FAILED;
03356 size_t fdlen = -1;
03357 SQLHSTMT stmt;
03358 char sql[PATH_MAX];
03359 char msgnums[20];
03360 char fn[PATH_MAX];
03361 char full_fn[PATH_MAX];
03362 char fmt[80]="";
03363 char *c;
03364 struct ast_config *cfg=NULL;
03365 struct odbc_obj *obj;
03366 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03367 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03368 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03369
03370 delete_file(dir, msgnum);
03371 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03372 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03373 return -1;
03374 }
03375
03376 do {
03377 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03378 c = strchr(fmt, '|');
03379 if (c)
03380 *c = '\0';
03381 if (!strcasecmp(fmt, "wav49"))
03382 strcpy(fmt, "WAV");
03383 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
03384 if (msgnum > -1)
03385 make_file(fn, sizeof(fn), dir, msgnum);
03386 else
03387 ast_copy_string(fn, dir, sizeof(fn));
03388 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03389 cfg = ast_config_load(full_fn, config_flags);
03390 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03391 fd = open(full_fn, O_RDWR);
03392 if (fd < 0) {
03393 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03394 res = -1;
03395 break;
03396 }
03397 if (cfg) {
03398 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03399 idata.context = "";
03400 }
03401 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03402 idata.macrocontext = "";
03403 }
03404 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03405 idata.callerid = "";
03406 }
03407 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03408 idata.origtime = "";
03409 }
03410 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03411 idata.duration = "";
03412 }
03413 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03414 idata.category = "";
03415 }
03416 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03417 idata.flag = "";
03418 }
03419 }
03420 fdlen = lseek(fd, 0, SEEK_END);
03421 lseek(fd, 0, SEEK_SET);
03422 printf("Length is %zd\n", fdlen);
03423 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0);
03424 if (fdm == MAP_FAILED) {
03425 ast_log(AST_LOG_WARNING, "Memory map failed!\n");
03426 res = -1;
03427 break;
03428 }
03429 idata.data = fdm;
03430 idata.datalen = idata.indlen = fdlen;
03431
03432 if (!ast_strlen_zero(idata.category))
03433 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)",odbc_table);
03434 else
03435 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)",odbc_table);
03436
03437 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03438 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03439 } else {
03440 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03441 res = -1;
03442 }
03443 } while (0);
03444 if (obj) {
03445 ast_odbc_release_obj(obj);
03446 }
03447 if (cfg)
03448 ast_config_destroy(cfg);
03449 if (fdm != MAP_FAILED)
03450 munmap(fdm, fdlen);
03451 if (fd > -1)
03452 close(fd);
03453 return res;
03454 }
03455
03456
03457
03458
03459
03460
03461
03462
03463
03464
03465
03466
03467
03468
03469 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03470 {
03471 SQLHSTMT stmt;
03472 char sql[PATH_MAX];
03473 char msgnums[20];
03474 char msgnumd[20];
03475 struct odbc_obj *obj;
03476 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03477 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03478
03479 delete_file(ddir, dmsg);
03480 obj = ast_odbc_request_obj(odbc_database, 0);
03481 if (obj) {
03482 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03483 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03484 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?",odbc_table);
03485 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03486 if (!stmt)
03487 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03488 else
03489 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03490 ast_odbc_release_obj(obj);
03491 } else
03492 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03493 return;
03494 }
03495
03496
03497
03498
03499
03500
03501
03502
03503
03504
03505
03506
03507 static int remove_file(char *dir, int msgnum)
03508 {
03509 char fn[PATH_MAX];
03510 char full_fn[PATH_MAX];
03511 char msgnums[80];
03512
03513 if (msgnum > -1) {
03514 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03515 make_file(fn, sizeof(fn), dir, msgnum);
03516 } else
03517 ast_copy_string(fn, dir, sizeof(fn));
03518 ast_filedelete(fn, NULL);
03519 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03520 unlink(full_fn);
03521 return 0;
03522 }
03523 #else
03524 #ifndef IMAP_STORAGE
03525
03526
03527
03528
03529
03530
03531
03532
03533
03534 static int count_messages(struct ast_vm_user *vmu, char *dir)
03535 {
03536
03537 int vmcount = 0;
03538 DIR *vmdir = NULL;
03539 struct dirent *vment = NULL;
03540
03541 if (vm_lock_path(dir))
03542 return ERROR_LOCK_PATH;
03543
03544 if ((vmdir = opendir(dir))) {
03545 while ((vment = readdir(vmdir))) {
03546 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
03547 vmcount++;
03548 }
03549 }
03550 closedir(vmdir);
03551 }
03552 ast_unlock_path(dir);
03553
03554 return vmcount;
03555 }
03556
03557
03558
03559
03560
03561
03562
03563
03564 static void rename_file(char *sfn, char *dfn)
03565 {
03566 char stxt[PATH_MAX];
03567 char dtxt[PATH_MAX];
03568 ast_filerename(sfn,dfn,NULL);
03569 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
03570 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
03571 if (ast_check_realtime("voicemail_data")) {
03572 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
03573 }
03574 rename(stxt, dtxt);
03575 }
03576
03577
03578
03579
03580
03581
03582
03583
03584
03585
03586
03587
03588 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03589 {
03590 int x;
03591 unsigned char map[MAXMSGLIMIT] = "";
03592 DIR *msgdir;
03593 struct dirent *msgdirent;
03594 int msgdirint;
03595
03596
03597
03598
03599
03600 if (!(msgdir = opendir(dir))) {
03601 return -1;
03602 }
03603
03604 while ((msgdirent = readdir(msgdir))) {
03605 if (sscanf(msgdirent->d_name, "msg%30d", &msgdirint) == 1 && msgdirint < MAXMSGLIMIT)
03606 map[msgdirint] = 1;
03607 }
03608 closedir(msgdir);
03609
03610 for (x = 0; x < vmu->maxmsg; x++) {
03611 if (map[x] == 0)
03612 break;
03613 }
03614
03615 return x - 1;
03616 }
03617
03618 #endif
03619 #endif
03620 #ifndef IMAP_STORAGE
03621
03622
03623
03624
03625
03626
03627
03628
03629
03630
03631 static int copy(char *infile, char *outfile)
03632 {
03633 int ifd;
03634 int ofd;
03635 int res;
03636 int len;
03637 char buf[4096];
03638
03639 #ifdef HARDLINK_WHEN_POSSIBLE
03640
03641 if (link(infile, outfile)) {
03642 #endif
03643 if ((ifd = open(infile, O_RDONLY)) < 0) {
03644 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
03645 return -1;
03646 }
03647 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
03648 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
03649 close(ifd);
03650 return -1;
03651 }
03652 do {
03653 len = read(ifd, buf, sizeof(buf));
03654 if (len < 0) {
03655 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
03656 close(ifd);
03657 close(ofd);
03658 unlink(outfile);
03659 }
03660 if (len) {
03661 res = write(ofd, buf, len);
03662 if (errno == ENOMEM || errno == ENOSPC || res != len) {
03663 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
03664 close(ifd);
03665 close(ofd);
03666 unlink(outfile);
03667 }
03668 }
03669 } while (len);
03670 close(ifd);
03671 close(ofd);
03672 return 0;
03673 #ifdef HARDLINK_WHEN_POSSIBLE
03674 } else {
03675
03676 return 0;
03677 }
03678 #endif
03679 }
03680
03681
03682
03683
03684
03685
03686
03687
03688
03689
03690 static void copy_plain_file(char *frompath, char *topath)
03691 {
03692 char frompath2[PATH_MAX], topath2[PATH_MAX];
03693 struct ast_variable *tmp,*var = NULL;
03694 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
03695 ast_filecopy(frompath, topath, NULL);
03696 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
03697 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
03698 if (ast_check_realtime("voicemail_data")) {
03699 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
03700
03701 for (tmp = var; tmp; tmp = tmp->next) {
03702 if (!strcasecmp(tmp->name, "origmailbox")) {
03703 origmailbox = tmp->value;
03704 } else if (!strcasecmp(tmp->name, "context")) {
03705 context = tmp->value;
03706 } else if (!strcasecmp(tmp->name, "macrocontext")) {
03707 macrocontext = tmp->value;
03708 } else if (!strcasecmp(tmp->name, "exten")) {
03709 exten = tmp->value;
03710 } else if (!strcasecmp(tmp->name, "priority")) {
03711 priority = tmp->value;
03712 } else if (!strcasecmp(tmp->name, "callerchan")) {
03713 callerchan = tmp->value;
03714 } else if (!strcasecmp(tmp->name, "callerid")) {
03715 callerid = tmp->value;
03716 } else if (!strcasecmp(tmp->name, "origdate")) {
03717 origdate = tmp->value;
03718 } else if (!strcasecmp(tmp->name, "origtime")) {
03719 origtime = tmp->value;
03720 } else if (!strcasecmp(tmp->name, "category")) {
03721 category = tmp->value;
03722 } else if (!strcasecmp(tmp->name, "duration")) {
03723 duration = tmp->value;
03724 }
03725 }
03726 ast_store_realtime("voicemail_data", "filename", topath, "origmailbox", origmailbox, "context", context, "macrocontext", macrocontext, "exten", exten, "priority", priority, "callerchan", callerchan, "callerid", callerid, "origdate", origdate, "origtime", origtime, "category", category, "duration", duration, SENTINEL);
03727 }
03728 copy(frompath2, topath2);
03729 ast_variables_destroy(var);
03730 }
03731 #endif
03732
03733
03734
03735
03736
03737
03738
03739
03740
03741 static int vm_delete(char *file)
03742 {
03743 char *txt;
03744 int txtsize = 0;
03745
03746 txtsize = (strlen(file) + 5)*sizeof(char);
03747 txt = alloca(txtsize);
03748
03749
03750
03751 if (ast_check_realtime("voicemail_data")) {
03752 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
03753 }
03754 snprintf(txt, txtsize, "%s.txt", file);
03755 unlink(txt);
03756 return ast_filedelete(file, NULL);
03757 }
03758
03759
03760
03761
03762 static int inbuf(struct baseio *bio, FILE *fi)
03763 {
03764 int l;
03765
03766 if (bio->ateof)
03767 return 0;
03768
03769 if ((l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
03770 if (ferror(fi))
03771 return -1;
03772
03773 bio->ateof = 1;
03774 return 0;
03775 }
03776
03777 bio->iolen= l;
03778 bio->iocp= 0;
03779
03780 return 1;
03781 }
03782
03783
03784
03785
03786 static int inchar(struct baseio *bio, FILE *fi)
03787 {
03788 if (bio->iocp>=bio->iolen) {
03789 if (!inbuf(bio, fi))
03790 return EOF;
03791 }
03792
03793 return bio->iobuf[bio->iocp++];
03794 }
03795
03796
03797
03798
03799 static int ochar(struct baseio *bio, int c, FILE *so)
03800 {
03801 if (bio->linelength >= BASELINELEN) {
03802 if (fputs(ENDL, so) == EOF) {
03803 return -1;
03804 }
03805
03806 bio->linelength= 0;
03807 }
03808
03809 if (putc(((unsigned char) c), so) == EOF) {
03810 return -1;
03811 }
03812
03813 bio->linelength++;
03814
03815 return 1;
03816 }
03817
03818
03819
03820
03821
03822
03823
03824
03825
03826
03827 static int base_encode(char *filename, FILE *so)
03828 {
03829 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
03830 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
03831 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
03832 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
03833 int i,hiteof= 0;
03834 FILE *fi;
03835 struct baseio bio;
03836
03837 memset(&bio, 0, sizeof(bio));
03838 bio.iocp = BASEMAXINLINE;
03839
03840 if (!(fi = fopen(filename, "rb"))) {
03841 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
03842 return -1;
03843 }
03844
03845 while (!hiteof){
03846 unsigned char igroup[3], ogroup[4];
03847 int c,n;
03848
03849 igroup[0]= igroup[1]= igroup[2]= 0;
03850
03851 for (n= 0;n<3;n++) {
03852 if ((c = inchar(&bio, fi)) == EOF) {
03853 hiteof= 1;
03854 break;
03855 }
03856
03857 igroup[n]= (unsigned char)c;
03858 }
03859
03860 if (n> 0) {
03861 ogroup[0]= dtable[igroup[0]>>2];
03862 ogroup[1]= dtable[((igroup[0]&3)<<4) | (igroup[1]>>4)];
03863 ogroup[2]= dtable[((igroup[1]&0xF)<<2) | (igroup[2]>>6)];
03864 ogroup[3]= dtable[igroup[2]&0x3F];
03865
03866 if (n<3) {
03867 ogroup[3]= '=';
03868
03869 if (n<2)
03870 ogroup[2]= '=';
03871 }
03872
03873 for (i= 0;i<4;i++)
03874 ochar(&bio, ogroup[i], so);
03875 }
03876 }
03877
03878 fclose(fi);
03879
03880 if (fputs(ENDL, so) == EOF) {
03881 return 0;
03882 }
03883
03884 return 1;
03885 }
03886
03887 static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *dur, char *date, char *passdata, size_t passdatasize, const char *category, const char *flag)
03888 {
03889 char callerid[256];
03890 char fromdir[256], fromfile[256];
03891 struct ast_config *msg_cfg;
03892 const char *origcallerid, *origtime;
03893 char origcidname[80], origcidnum[80], origdate[80];
03894 int inttime;
03895 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03896
03897
03898 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
03899 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
03900 snprintf(passdata, passdatasize, "%d", msgnum);
03901 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", passdata);
03902 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
03903 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
03904 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
03905 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
03906 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
03907 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
03908 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
03909 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
03910 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
03911
03912
03913 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
03914 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
03915 if (strlen(fromfile) < sizeof(fromfile) - 5) {
03916 strcat(fromfile, ".txt");
03917 }
03918 if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
03919 if (option_debug > 0) {
03920 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
03921 }
03922 return;
03923 }
03924
03925 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
03926 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
03927 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
03928 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
03929 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
03930 }
03931
03932 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
03933 struct timeval tv = { inttime, };
03934 struct ast_tm tm;
03935 ast_localtime(&tv, &tm, NULL);
03936 ast_strftime(origdate, sizeof(origdate), emaildateformat, &tm);
03937 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
03938 }
03939 ast_config_destroy(msg_cfg);
03940 }
03941
03942
03943
03944
03945
03946
03947
03948
03949 static char *quote(const char *from, char *to, size_t len)
03950 {
03951 char *ptr = to;
03952 *ptr++ = '"';
03953 for (; ptr < to + len - 1; from++) {
03954 if (*from == '"')
03955 *ptr++ = '\\';
03956 else if (*from == '\0')
03957 break;
03958 *ptr++ = *from;
03959 }
03960 if (ptr < to + len - 1)
03961 *ptr++ = '"';
03962 *ptr = '\0';
03963 return to;
03964 }
03965
03966
03967
03968
03969
03970 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
03971 {
03972 const struct vm_zone *z = NULL;
03973 struct timeval t = ast_tvnow();
03974
03975
03976 if (!ast_strlen_zero(vmu->zonetag)) {
03977
03978 AST_LIST_LOCK(&zones);
03979 AST_LIST_TRAVERSE(&zones, z, list) {
03980 if (!strcmp(z->name, vmu->zonetag))
03981 break;
03982 }
03983 AST_LIST_UNLOCK(&zones);
03984 }
03985 ast_localtime(&t, tm, z ? z->timezone : NULL);
03986 return tm;
03987 }
03988
03989
03990
03991
03992
03993 static int check_mime(const char *str)
03994 {
03995 for (; *str; str++) {
03996 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
03997 return 1;
03998 }
03999 }
04000 return 0;
04001 }
04002
04003
04004
04005
04006
04007
04008
04009
04010
04011
04012
04013
04014
04015
04016
04017
04018
04019 static char *encode_mime_str(const char *start, char *end, size_t endsize, size_t preamble, size_t postamble)
04020 {
04021 char tmp[80];
04022 int first_section = 1;
04023 size_t endlen = 0, tmplen = 0;
04024 *end = '\0';
04025
04026 tmplen = snprintf(tmp, sizeof(tmp), "=?%s?Q?", charset);
04027 for (; *start; start++) {
04028 int need_encoding = 0;
04029 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04030 need_encoding = 1;
04031 }
04032 if ((first_section && need_encoding && preamble + tmplen > 70) ||
04033 (first_section && !need_encoding && preamble + tmplen > 72) ||
04034 (!first_section && need_encoding && tmplen > 70) ||
04035 (!first_section && !need_encoding && tmplen > 72)) {
04036
04037 endlen += snprintf(end + endlen, endsize - endlen, "%s%s?=", first_section ? "" : " ", tmp);
04038 tmplen = snprintf(tmp, sizeof(tmp), "=?%s?Q?", charset);
04039 first_section = 0;
04040 }
04041 if (need_encoding && *start == ' ') {
04042 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "_");
04043 } else if (need_encoding) {
04044 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "=%hhX", *start);
04045 } else {
04046 tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "%c", *start);
04047 }
04048 }
04049 snprintf(end + endlen, endsize - endlen, "%s%s?=%s", first_section ? "" : " ", tmp, endlen + postamble > 74 ? " " : "");
04050 return end;
04051 }
04052
04053
04054
04055
04056
04057
04058
04059
04060
04061
04062
04063
04064
04065
04066
04067
04068
04069
04070
04071
04072
04073 static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag)
04074 {
04075 char date[256];
04076 char host[MAXHOSTNAMELEN] = "";
04077 char who[256];
04078 char bound[256];
04079 char dur[256];
04080 struct ast_tm tm;
04081 char enc_cidnum[256] = "", enc_cidname[256] = "";
04082 char *passdata = NULL, *passdata2;
04083 size_t len_passdata = 0, len_passdata2, tmplen;
04084 char *greeting_attachment;
04085 char filename[256];
04086
04087
04088
04089 len_passdata2 = strlen(vmu->fullname);
04090 if (emailsubject && (tmplen = strlen(emailsubject)) > len_passdata2) {
04091 len_passdata2 = tmplen;
04092 }
04093 if ((tmplen = strlen(fromstring)) > len_passdata2) {
04094 len_passdata2 = tmplen;
04095 }
04096 len_passdata2 = len_passdata2 * 3 + 200;
04097 passdata2 = alloca(len_passdata2);
04098
04099 if (cidnum) {
04100 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04101 }
04102 if (cidname) {
04103 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04104 }
04105 gethostname(host, sizeof(host) - 1);
04106
04107 if (strchr(srcemail, '@'))
04108 ast_copy_string(who, srcemail, sizeof(who));
04109 else
04110 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04111
04112 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04113 if (greeting_attachment)
04114 *greeting_attachment++ = '\0';
04115
04116 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04117 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04118 fprintf(p, "Date: %s" ENDL, date);
04119
04120
04121 ast_strftime(date, sizeof(date), emaildateformat, &tm);
04122
04123 if (!ast_strlen_zero(fromstring)) {
04124 struct ast_channel *ast;
04125 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
04126 char *ptr;
04127 memset(passdata2, 0, len_passdata2);
04128 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, passdata2, len_passdata2, category, flag);
04129 pbx_substitute_variables_helper(ast, fromstring, passdata2, len_passdata2);
04130 len_passdata = strlen(passdata2) * 3 + 300;
04131 passdata = alloca(len_passdata);
04132 if (check_mime(passdata2)) {
04133 int first_line = 1;
04134 encode_mime_str(passdata2, passdata, len_passdata, strlen("From: "), strlen(who) + 3);
04135 while ((ptr = strchr(passdata, ' '))) {
04136 *ptr = '\0';
04137 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", passdata);
04138 first_line = 0;
04139 passdata = ptr + 1;
04140 }
04141 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", passdata, who);
04142 } else {
04143 fprintf(p, "From: %s <%s>" ENDL, quote(passdata2, passdata, len_passdata), who);
04144 }
04145 ast_channel_free(ast);
04146 } else {
04147 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04148 }
04149 } else {
04150 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04151 }
04152
04153 if (check_mime(vmu->fullname)) {
04154 int first_line = 1;
04155 char *ptr;
04156 encode_mime_str(vmu->fullname, passdata2, len_passdata2, strlen("To: "), strlen(vmu->email) + 3);
04157 while ((ptr = strchr(passdata2, ' '))) {
04158 *ptr = '\0';
04159 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", passdata2);
04160 first_line = 0;
04161 passdata2 = ptr + 1;
04162 }
04163 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", passdata2, vmu->email);
04164 } else {
04165 fprintf(p, "To: %s <%s>" ENDL, quote(vmu->fullname, passdata2, len_passdata2), vmu->email);
04166 }
04167 if (!ast_strlen_zero(emailsubject)) {
04168 struct ast_channel *ast;
04169 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
04170 int vmlen = strlen(emailsubject) * 3 + 200;
04171
04172 if (vmlen > len_passdata) {
04173 passdata = alloca(vmlen);
04174 len_passdata = vmlen;
04175 }
04176
04177 memset(passdata, 0, len_passdata);
04178 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, len_passdata, category, flag);
04179 pbx_substitute_variables_helper(ast, emailsubject, passdata, len_passdata);
04180 if (check_mime(passdata)) {
04181 int first_line = 1;
04182 char *ptr;
04183 encode_mime_str(passdata, passdata2, len_passdata2, strlen("Subject: "), 0);
04184 while ((ptr = strchr(passdata2, ' '))) {
04185 *ptr = '\0';
04186 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2);
04187 first_line = 0;
04188 passdata2 = ptr + 1;
04189 }
04190 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2);
04191 } else {
04192 fprintf(p, "Subject: %s" ENDL, passdata);
04193 }
04194 ast_channel_free(ast);
04195 } else {
04196 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04197 }
04198 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04199 if (ast_strlen_zero(flag)) {
04200 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04201 } else {
04202 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04203 }
04204 } else {
04205 if (ast_strlen_zero(flag)) {
04206 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04207 } else {
04208 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04209 }
04210 }
04211
04212 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1, (unsigned int)ast_random(), mailbox, (int)getpid(), host);
04213 if (imap) {
04214
04215 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04216
04217 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04218 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04219 #ifdef IMAP_STORAGE
04220 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04221 #else
04222 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04223 #endif
04224
04225 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04226 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04227 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04228 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04229 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04230 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04231 if (!ast_strlen_zero(category)) {
04232 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04233 } else {
04234 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04235 }
04236 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04237 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04238 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long)time(NULL));
04239 }
04240 if (!ast_strlen_zero(cidnum)) {
04241 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04242 }
04243 if (!ast_strlen_zero(cidname)) {
04244 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04245 }
04246 fprintf(p, "MIME-Version: 1.0" ENDL);
04247 if (attach_user_voicemail) {
04248
04249 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox, (int)getpid(), (unsigned int)ast_random());
04250
04251 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04252 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04253 fprintf(p, "--%s" ENDL, bound);
04254 }
04255 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04256 if (emailbody) {
04257 struct ast_channel *ast;
04258 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
04259 char *passdata;
04260 int vmlen = strlen(emailbody)*3 + 200;
04261 passdata = alloca(vmlen);
04262 memset(passdata, 0, vmlen);
04263 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
04264 pbx_substitute_variables_helper(ast, emailbody, passdata, vmlen);
04265 #ifdef IMAP_STORAGE
04266 {
04267
04268 char *line = passdata, *next;
04269 do {
04270
04271 if ((next = strchr(line, '\n'))) {
04272 *next++ = '\0';
04273 }
04274 fprintf(p, "%s" ENDL, line);
04275 line = next;
04276 } while (!ast_strlen_zero(line));
04277 }
04278 #else
04279 fprintf(p, "%s" ENDL, passdata);
04280 #endif
04281 ast_channel_free(ast);
04282 } else
04283 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04284 } else if (msgnum > -1) {
04285 if (strcmp(vmu->mailbox, mailbox)) {
04286
04287 struct ast_config *msg_cfg;
04288 const char *v;
04289 int inttime;
04290 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04291 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04292
04293 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04294 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04295 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04296 strcat(fromfile, ".txt");
04297 }
04298 if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
04299 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04300 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04301 }
04302
04303
04304
04305 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04306 struct timeval tv = { inttime, };
04307 struct ast_tm tm;
04308 ast_localtime(&tv, &tm, NULL);
04309 ast_strftime(origdate, sizeof(origdate), emaildateformat, &tm);
04310 }
04311 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04312 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04313 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04314 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04315 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04316 date, origcallerid, origdate);
04317 ast_config_destroy(msg_cfg);
04318 } else {
04319 goto plain_message;
04320 }
04321 } else {
04322 plain_message:
04323 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04324 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04325 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04326 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04327 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04328 }
04329 } else {
04330 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04331 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04332 }
04333
04334 if (imap || attach_user_voicemail) {
04335 if (!ast_strlen_zero(attach2)) {
04336 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04337 ast_debug(5, "creating second attachment filename %s\n", filename);
04338 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04339 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04340 ast_debug(5, "creating attachment filename %s\n", filename);
04341 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04342 } else {
04343 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04344 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04345 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04346 }
04347 }
04348 }
04349
04350 static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum)
04351 {
04352 char tmpdir[256], newtmp[256];
04353 char fname[256];
04354 char tmpcmd[256];
04355 int tmpfd = -1;
04356
04357
04358 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04359
04360 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04361 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04362 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04363 tmpfd = mkstemp(newtmp);
04364 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04365 ast_debug(3, "newtmp: %s\n", newtmp);
04366 if (tmpfd > -1) {
04367 int soxstatus;
04368 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04369 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04370 attach = newtmp;
04371 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04372 } else {
04373 ast_log(LOG_WARNING, "Sox failed to reencode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04374 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04375 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04376 }
04377 }
04378 }
04379 fprintf(p, "--%s" ENDL, bound);
04380 if (msgnum > -1)
04381 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04382 else
04383 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04384 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04385 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04386 if (msgnum > -1)
04387 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04388 else
04389 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04390 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04391 base_encode(fname, p);
04392 if (last)
04393 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04394 if (tmpfd > -1) {
04395 unlink(fname);
04396 close(tmpfd);
04397 unlink(newtmp);
04398 }
04399 return 0;
04400 }
04401 #undef ENDL
04402
04403 static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, const char *flag)
04404 {
04405 FILE *p=NULL;
04406 char tmp[80] = "/tmp/astmail-XXXXXX";
04407 char tmp2[256];
04408
04409 if (vmu && ast_strlen_zero(vmu->email)) {
04410 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04411 return(0);
04412 }
04413 if (!strcmp(format, "wav49"))
04414 format = "WAV";
04415 ast_debug(3, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
04416
04417
04418 if ((p = vm_mkftemp(tmp)) == NULL) {
04419 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04420 return -1;
04421 } else {
04422 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04423 fclose(p);
04424 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04425 ast_safe_system(tmp2);
04426 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04427 }
04428 return 0;
04429 }
04430
04431 static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu, const char *category, const char *flag)
04432 {
04433 char date[256];
04434 char host[MAXHOSTNAMELEN] = "";
04435 char who[256];
04436 char dur[PATH_MAX];
04437 char tmp[80] = "/tmp/astmail-XXXXXX";
04438 char tmp2[PATH_MAX];
04439 struct ast_tm tm;
04440 FILE *p;
04441
04442 if ((p = vm_mkftemp(tmp)) == NULL) {
04443 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04444 return -1;
04445 }
04446 gethostname(host, sizeof(host)-1);
04447 if (strchr(srcemail, '@'))
04448 ast_copy_string(who, srcemail, sizeof(who));
04449 else
04450 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04451 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04452 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04453 fprintf(p, "Date: %s\n", date);
04454
04455 if (*pagerfromstring) {
04456 struct ast_channel *ast;
04457 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
04458 char *passdata;
04459 int vmlen = strlen(fromstring)*3 + 200;
04460 passdata = alloca(vmlen);
04461 memset(passdata, 0, vmlen);
04462 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
04463 pbx_substitute_variables_helper(ast, pagerfromstring, passdata, vmlen);
04464 fprintf(p, "From: %s <%s>\n", passdata, who);
04465 ast_channel_free(ast);
04466 } else
04467 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04468 } else
04469 fprintf(p, "From: Asterisk PBX <%s>\n", who);
04470 fprintf(p, "To: %s\n", pager);
04471 if (pagersubject) {
04472 struct ast_channel *ast;
04473 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
04474 char *passdata;
04475 int vmlen = strlen(pagersubject) * 3 + 200;
04476 passdata = alloca(vmlen);
04477 memset(passdata, 0, vmlen);
04478 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
04479 pbx_substitute_variables_helper(ast, pagersubject, passdata, vmlen);
04480 fprintf(p, "Subject: %s\n\n", passdata);
04481 ast_channel_free(ast);
04482 } else
04483 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04484 } else {
04485 if (ast_strlen_zero(flag)) {
04486 fprintf(p, "Subject: New VM\n\n");
04487 } else {
04488 fprintf(p, "Subject: New %s VM\n\n", flag);
04489 }
04490 }
04491
04492 ast_strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
04493 if (pagerbody) {
04494 struct ast_channel *ast;
04495 if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
04496 char *passdata;
04497 int vmlen = strlen(pagerbody) * 3 + 200;
04498 passdata = alloca(vmlen);
04499 memset(passdata, 0, vmlen);
04500 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
04501 pbx_substitute_variables_helper(ast, pagerbody, passdata, vmlen);
04502 fprintf(p, "%s\n", passdata);
04503 ast_channel_free(ast);
04504 } else
04505 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04506 } else {
04507 fprintf(p, "New %s long %s msg in box %s\n"
04508 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
04509 }
04510 fclose(p);
04511 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04512 ast_safe_system(tmp2);
04513 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
04514 return 0;
04515 }
04516
04517
04518
04519
04520
04521
04522
04523
04524
04525
04526 static int get_date(char *s, int len)
04527 {
04528 struct ast_tm tm;
04529 struct timeval t = ast_tvnow();
04530
04531 ast_localtime(&t, &tm, "UTC");
04532
04533 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
04534 }
04535
04536 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
04537 {
04538 int res;
04539 char fn[PATH_MAX];
04540 char dest[PATH_MAX];
04541
04542 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
04543
04544 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
04545 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
04546 return -1;
04547 }
04548
04549 RETRIEVE(fn, -1, ext, context);
04550 if (ast_fileexists(fn, NULL, NULL) > 0) {
04551 res = ast_stream_and_wait(chan, fn, ecodes);
04552 if (res) {
04553 DISPOSE(fn, -1);
04554 return res;
04555 }
04556 } else {
04557
04558 DISPOSE(fn, -1);
04559 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
04560 if (res)
04561 return res;
04562 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
04563 if (res)
04564 return res;
04565 }
04566 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
04567 return res;
04568 }
04569
04570 static void free_zone(struct vm_zone *z)
04571 {
04572 ast_free(z);
04573 }
04574
04575 #ifdef ODBC_STORAGE
04576 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
04577 {
04578 int x = -1;
04579 int res;
04580 SQLHSTMT stmt = NULL;
04581 char sql[PATH_MAX];
04582 char rowdata[20];
04583 char tmp[PATH_MAX] = "";
04584 struct odbc_obj *obj = NULL;
04585 char *context;
04586 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
04587
04588 if (newmsgs)
04589 *newmsgs = 0;
04590 if (oldmsgs)
04591 *oldmsgs = 0;
04592 if (urgentmsgs)
04593 *urgentmsgs = 0;
04594
04595
04596 if (ast_strlen_zero(mailbox))
04597 return 0;
04598
04599 ast_copy_string(tmp, mailbox, sizeof(tmp));
04600
04601 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
04602 int u, n, o;
04603 char *next, *remaining = tmp;
04604 while ((next = strsep(&remaining, " ,"))) {
04605 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
04606 return -1;
04607 }
04608 if (urgentmsgs) {
04609 *urgentmsgs += u;
04610 }
04611 if (newmsgs) {
04612 *newmsgs += n;
04613 }
04614 if (oldmsgs) {
04615 *oldmsgs += o;
04616 }
04617 }
04618 return 0;
04619 }
04620
04621 context = strchr(tmp, '@');
04622 if (context) {
04623 *context = '\0';
04624 context++;
04625 } else
04626 context = "default";
04627
04628 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
04629 do {
04630 if (newmsgs) {
04631 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
04632 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
04633 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
04634 break;
04635 }
04636 res = SQLFetch(stmt);
04637 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04638 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
04639 break;
04640 }
04641 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
04642 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04643 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
04644 break;
04645 }
04646 *newmsgs = atoi(rowdata);
04647 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04648 }
04649
04650 if (oldmsgs) {
04651 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
04652 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
04653 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
04654 break;
04655 }
04656 res = SQLFetch(stmt);
04657 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04658 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
04659 break;
04660 }
04661 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
04662 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04663 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
04664 break;
04665 }
04666 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
04667 *oldmsgs = atoi(rowdata);
04668 }
04669
04670 if (urgentmsgs) {
04671 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
04672 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
04673 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
04674 break;
04675 }
04676 res = SQLFetch(stmt);
04677 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04678 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
04679 break;
04680 }
04681 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
04682 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04683 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
04684 break;
04685 }
04686 *urgentmsgs = atoi(rowdata);
04687 }
04688
04689 x = 0;
04690 } while (0);
04691 } else {
04692 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
04693 }
04694
04695 if (stmt) {
04696 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04697 }
04698 if (obj) {
04699 ast_odbc_release_obj(obj);
04700 }
04701
04702 return x;
04703 }
04704
04705
04706
04707
04708
04709
04710
04711
04712
04713
04714 static int messagecount(const char *context, const char *mailbox, const char *folder)
04715 {
04716 struct odbc_obj *obj = NULL;
04717 int nummsgs = 0;
04718 int res;
04719 SQLHSTMT stmt = NULL;
04720 char sql[PATH_MAX];
04721 char rowdata[20];
04722 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
04723 if (!folder)
04724 folder = "INBOX";
04725
04726 if (ast_strlen_zero(mailbox))
04727 return 0;
04728
04729 obj = ast_odbc_request_obj(odbc_database, 0);
04730 if (obj) {
04731 if (!strcmp(folder, "INBOX")) {
04732 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/INBOX' OR dir = '%s%s/%s/Urgent'", odbc_table, VM_SPOOL_DIR, context, mailbox, VM_SPOOL_DIR, context, mailbox);
04733 } else {
04734 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
04735 }
04736 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
04737 if (!stmt) {
04738 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
04739 goto yuck;
04740 }
04741 res = SQLFetch(stmt);
04742 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04743 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
04744 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04745 goto yuck;
04746 }
04747 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
04748 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04749 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
04750 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04751 goto yuck;
04752 }
04753 nummsgs = atoi(rowdata);
04754 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04755 } else
04756 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
04757
04758 yuck:
04759 if (obj)
04760 ast_odbc_release_obj(obj);
04761 return nummsgs;
04762 }
04763
04764
04765
04766
04767
04768
04769
04770
04771
04772 static int has_voicemail(const char *mailbox, const char *folder)
04773 {
04774 char tmp[256], *tmp2 = tmp, *box, *context;
04775 ast_copy_string(tmp, mailbox, sizeof(tmp));
04776 while ((context = box = strsep(&tmp2, ",&"))) {
04777 strsep(&context, "@");
04778 if (ast_strlen_zero(context))
04779 context = "default";
04780 if (messagecount(context, box, folder))
04781 return 1;
04782 }
04783 return 0;
04784 }
04785 #endif
04786 #ifndef IMAP_STORAGE
04787
04788
04789
04790
04791
04792
04793
04794
04795
04796
04797
04798
04799
04800
04801
04802 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, const char *flag)
04803 {
04804 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
04805 const char *frombox = mbox(imbox);
04806 int recipmsgnum;
04807 int res = 0;
04808
04809 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
04810
04811 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
04812 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "Urgent");
04813 } else {
04814 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
04815 }
04816
04817 if (!dir)
04818 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
04819 else
04820 ast_copy_string(fromdir, dir, sizeof(fromdir));
04821
04822 make_file(frompath, sizeof(frompath), fromdir, msgnum);
04823 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
04824
04825 if (vm_lock_path(todir))
04826 return ERROR_LOCK_PATH;
04827
04828 recipmsgnum = last_message_index(recip, todir) + 1;
04829 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
04830 make_file(topath, sizeof(topath), todir, recipmsgnum);
04831 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
04832 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
04833 } else {
04834
04835
04836
04837
04838
04839 copy_plain_file(frompath, topath);
04840 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
04841 vm_delete(topath);
04842 }
04843 } else {
04844 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
04845 res = -1;
04846 }
04847 ast_unlock_path(todir);
04848 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), flag);
04849
04850 return res;
04851 }
04852 #endif
04853 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
04854
04855 static int messagecount(const char *context, const char *mailbox, const char *folder)
04856 {
04857 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
04858 }
04859
04860 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
04861 {
04862 DIR *dir;
04863 struct dirent *de;
04864 char fn[256];
04865 int ret = 0;
04866
04867
04868 if (ast_strlen_zero(mailbox))
04869 return 0;
04870
04871 if (ast_strlen_zero(folder))
04872 folder = "INBOX";
04873 if (ast_strlen_zero(context))
04874 context = "default";
04875
04876 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
04877
04878 if (!(dir = opendir(fn)))
04879 return 0;
04880
04881 while ((de = readdir(dir))) {
04882 if (!strncasecmp(de->d_name, "msg", 3)) {
04883 if (shortcircuit) {
04884 ret = 1;
04885 break;
04886 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
04887 ret++;
04888 }
04889 }
04890 }
04891
04892 closedir(dir);
04893
04894 return ret;
04895 }
04896
04897
04898
04899
04900
04901
04902
04903
04904
04905
04906 static int has_voicemail(const char *mailbox, const char *folder)
04907 {
04908 char tmp[256], *tmp2 = tmp, *box, *context;
04909 ast_copy_string(tmp, mailbox, sizeof(tmp));
04910 if (ast_strlen_zero(folder)) {
04911 folder = "INBOX";
04912 }
04913 while ((box = strsep(&tmp2, ",&"))) {
04914 if ((context = strchr(box, '@')))
04915 *context++ = '\0';
04916 else
04917 context = "default";
04918 if (__has_voicemail(context, box, folder, 1))
04919 return 1;
04920
04921 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
04922 return 1;
04923 }
04924 }
04925 return 0;
04926 }
04927
04928
04929 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
04930 {
04931 char tmp[256];
04932 char *context;
04933
04934
04935 if (ast_strlen_zero(mailbox))
04936 return 0;
04937
04938 if (newmsgs)
04939 *newmsgs = 0;
04940 if (oldmsgs)
04941 *oldmsgs = 0;
04942 if (urgentmsgs)
04943 *urgentmsgs = 0;
04944
04945 if (strchr(mailbox, ',')) {
04946 int tmpnew, tmpold, tmpurgent;
04947 char *mb, *cur;
04948
04949 ast_copy_string(tmp, mailbox, sizeof(tmp));
04950 mb = tmp;
04951 while ((cur = strsep(&mb, ", "))) {
04952 if (!ast_strlen_zero(cur)) {
04953 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
04954 return -1;
04955 else {
04956 if (newmsgs)
04957 *newmsgs += tmpnew;
04958 if (oldmsgs)
04959 *oldmsgs += tmpold;
04960 if (urgentmsgs)
04961 *urgentmsgs += tmpurgent;
04962 }
04963 }
04964 }
04965 return 0;
04966 }
04967
04968 ast_copy_string(tmp, mailbox, sizeof(tmp));
04969
04970 if ((context = strchr(tmp, '@')))
04971 *context++ = '\0';
04972 else
04973 context = "default";
04974
04975 if (newmsgs)
04976 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
04977 if (oldmsgs)
04978 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
04979 if (urgentmsgs)
04980 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
04981
04982 return 0;
04983 }
04984
04985 #endif
04986
04987
04988 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
04989 {
04990 int urgentmsgs = 0;
04991 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
04992 if (newmsgs) {
04993 *newmsgs += urgentmsgs;
04994 }
04995 return res;
04996 }
04997
04998 static void run_externnotify(char *context, char *extension, const char *flag)
04999 {
05000 char arguments[255];
05001 char ext_context[256] = "";
05002 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05003 struct ast_smdi_mwi_message *mwi_msg;
05004
05005 if (!ast_strlen_zero(context))
05006 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05007 else
05008 ast_copy_string(ext_context, extension, sizeof(ext_context));
05009
05010 if (smdi_iface) {
05011 if (ast_app_has_voicemail(ext_context, NULL))
05012 ast_smdi_mwi_set(smdi_iface, extension);
05013 else
05014 ast_smdi_mwi_unset(smdi_iface, extension);
05015
05016 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05017 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05018 if (!strncmp(mwi_msg->cause, "INV", 3))
05019 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05020 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05021 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05022 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05023 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05024 } else {
05025 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05026 }
05027 }
05028
05029 if (!ast_strlen_zero(externnotify)) {
05030 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05031 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05032 } else {
05033 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &", externnotify, context, extension, newvoicemails, oldvoicemails, urgentvoicemails);
05034 ast_debug(1, "Executing %s\n", arguments);
05035 ast_safe_system(arguments);
05036 }
05037 }
05038 }
05039
05040
05041
05042
05043
05044
05045 struct leave_vm_options {
05046 unsigned int flags;
05047 signed char record_gain;
05048 char *exitcontext;
05049 };
05050
05051
05052
05053
05054
05055
05056
05057
05058
05059
05060
05061 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05062 {
05063 #ifdef IMAP_STORAGE
05064 int newmsgs, oldmsgs;
05065 #else
05066 char urgdir[PATH_MAX];
05067 #endif
05068 char txtfile[PATH_MAX];
05069 char tmptxtfile[PATH_MAX];
05070 struct vm_state *vms = NULL;
05071 char callerid[256];
05072 FILE *txt;
05073 char date[256];
05074 int txtdes;
05075 int res = 0;
05076 int msgnum;
05077 int duration = 0;
05078 int ausemacro = 0;
05079 int ousemacro = 0;
05080 int ouseexten = 0;
05081 int rtmsgid = 0;
05082 char tmpid[16];
05083 char tmpdur[16];
05084 char priority[16];
05085 char origtime[16];
05086 char dir[PATH_MAX];
05087 char tmpdir[PATH_MAX];
05088 char fn[PATH_MAX];
05089 char prefile[PATH_MAX] = "";
05090 char tempfile[PATH_MAX] = "";
05091 char ext_context[256] = "";
05092 char fmt[80];
05093 char *context;
05094 char ecodes[17] = "#";
05095 struct ast_str *tmp = ast_str_create(16);
05096 char *tmpptr;
05097 struct ast_vm_user *vmu;
05098 struct ast_vm_user svm;
05099 const char *category = NULL;
05100 const char *code;
05101 const char *alldtmf = "0123456789ABCD*#";
05102 char flag[80];
05103
05104 ast_str_set(&tmp, 0, "%s", ext);
05105 ext = ast_str_buffer(tmp);
05106 if ((context = strchr(ext, '@'))) {
05107 *context++ = '\0';
05108 tmpptr = strchr(context, '&');
05109 } else {
05110 tmpptr = strchr(ext, '&');
05111 }
05112
05113 if (tmpptr)
05114 *tmpptr++ = '\0';
05115
05116 ast_channel_lock(chan);
05117 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05118 category = ast_strdupa(category);
05119 }
05120 ast_channel_unlock(chan);
05121
05122 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05123 ast_copy_string(flag, "Urgent", sizeof(flag));
05124 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05125 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05126 } else {
05127 flag[0] = '\0';
05128 }
05129
05130 ast_debug(3, "Before find_user\n");
05131 if (!(vmu = find_user(&svm, context, ext))) {
05132 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05133 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05134 ast_free(tmp);
05135 return res;
05136 }
05137
05138 if (strcmp(vmu->context, "default"))
05139 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05140 else
05141 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05142
05143
05144
05145
05146
05147
05148 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05149 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05150 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05151 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05152 }
05153
05154
05155
05156
05157 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05158 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05159 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05160 ast_free(tmp);
05161 return -1;
05162 }
05163 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05164 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05165 ast_copy_string(prefile, tempfile, sizeof(prefile));
05166
05167 DISPOSE(tempfile, -1);
05168
05169 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05170
05171
05172 if (ast_test_flag(vmu, VM_OPERATOR)) {
05173 if (!ast_strlen_zero(vmu->exit)) {
05174 if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num)) {
05175 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05176 ouseexten = 1;
05177 }
05178 } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num)) {
05179 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05180 ouseexten = 1;
05181 } else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) {
05182 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05183 ousemacro = 1;
05184 }
05185 }
05186
05187 if (!ast_strlen_zero(vmu->exit)) {
05188 if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num))
05189 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05190 } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num))
05191 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05192 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) {
05193 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05194 ausemacro = 1;
05195 }
05196
05197 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05198 for (code = alldtmf; *code; code++) {
05199 char e[2] = "";
05200 e[0] = *code;
05201 if (strchr(ecodes, e[0]) == NULL && ast_canmatch_extension(chan, chan->context, e, 1, chan->cid.cid_num))
05202 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05203 }
05204 }
05205
05206
05207 if (!ast_strlen_zero(prefile)) {
05208 #ifdef ODBC_STORAGE
05209 int success =
05210 #endif
05211 RETRIEVE(prefile, -1, ext, context);
05212 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05213 if (ast_streamfile(chan, prefile, chan->language) > -1)
05214 res = ast_waitstream(chan, ecodes);
05215 #ifdef ODBC_STORAGE
05216 if (success == -1) {
05217
05218 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05219 store_file(prefile, vmu->mailbox, vmu->context, -1);
05220 }
05221 #endif
05222 } else {
05223 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05224 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05225 }
05226 DISPOSE(prefile, -1);
05227 if (res < 0) {
05228 ast_debug(1, "Hang up during prefile playback\n");
05229 free_user(vmu);
05230 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05231 ast_free(tmp);
05232 return -1;
05233 }
05234 }
05235 if (res == '#') {
05236
05237 ast_set_flag(options, OPT_SILENT);
05238 res = 0;
05239 }
05240 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05241 res = ast_stream_and_wait(chan, INTRO, ecodes);
05242 if (res == '#') {
05243 ast_set_flag(options, OPT_SILENT);
05244 res = 0;
05245 }
05246 }
05247 if (res > 0)
05248 ast_stopstream(chan);
05249
05250
05251 if (res == '*') {
05252 chan->exten[0] = 'a';
05253 chan->exten[1] = '\0';
05254 if (!ast_strlen_zero(vmu->exit)) {
05255 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05256 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05257 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05258 }
05259 chan->priority = 0;
05260 free_user(vmu);
05261 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05262 ast_free(tmp);
05263 return 0;
05264 }
05265
05266
05267 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05268 transfer:
05269 if (ouseexten || ousemacro) {
05270 chan->exten[0] = 'o';
05271 chan->exten[1] = '\0';
05272 if (!ast_strlen_zero(vmu->exit)) {
05273 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05274 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05275 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05276 }
05277 ast_play_and_wait(chan, "transfer");
05278 chan->priority = 0;
05279 free_user(vmu);
05280 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05281 }
05282 ast_free(tmp);
05283 return OPERATOR_EXIT;
05284 }
05285
05286
05287 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05288 if (!ast_strlen_zero(options->exitcontext))
05289 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05290 free_user(vmu);
05291 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05292 ast_free(tmp);
05293 return res;
05294 }
05295
05296 if (res < 0) {
05297 free_user(vmu);
05298 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05299 ast_free(tmp);
05300 return -1;
05301 }
05302
05303 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05304 if (!ast_strlen_zero(fmt)) {
05305 msgnum = 0;
05306
05307 #ifdef IMAP_STORAGE
05308
05309
05310 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05311 if (res < 0) {
05312 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05313 ast_free(tmp);
05314 return -1;
05315 }
05316 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05317
05318
05319
05320
05321 if (!(vms = create_vm_state_from_user(vmu))) {
05322 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05323 ast_free(tmp);
05324 return -1;
05325 }
05326 }
05327 vms->newmessages++;
05328
05329
05330 msgnum = newmsgs + oldmsgs;
05331 ast_debug(3, "Messagecount set to %d\n",msgnum);
05332 snprintf(fn, sizeof(fn), "%s/imap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05333
05334 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05335
05336 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05337 goto leave_vm_out;
05338 }
05339 #else
05340 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05341 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05342 if (!res)
05343 res = ast_waitstream(chan, "");
05344 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05345 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05346 inprocess_count(vmu->mailbox, vmu->context, -1);
05347 goto leave_vm_out;
05348 }
05349
05350 #endif
05351 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05352 txtdes = mkstemp(tmptxtfile);
05353 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05354 if (txtdes < 0) {
05355 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05356 if (!res)
05357 res = ast_waitstream(chan, "");
05358 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05359 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05360 inprocess_count(vmu->mailbox, vmu->context, -1);
05361 goto leave_vm_out;
05362 }
05363
05364
05365 if (res >= 0) {
05366
05367 res = ast_stream_and_wait(chan, "beep", "");
05368 }
05369
05370
05371 if (ast_check_realtime("voicemail_data")) {
05372 snprintf(priority, sizeof(priority), "%d", chan->priority);
05373 snprintf(origtime, sizeof(origtime), "%ld", (long)time(NULL));
05374 get_date(date, sizeof(date));
05375 rtmsgid = ast_store_realtime("voicemail_data", "origmailbox", ext, "context", chan->context, "macrocontext", chan->macrocontext, "exten", chan->exten, "priority", priority, "callerchan", chan->name, "callerid", ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"), "origdate", date, "origtime", origtime, "category", S_OR(category,""), SENTINEL);
05376 }
05377
05378
05379 txt = fdopen(txtdes, "w+");
05380 if (txt) {
05381 get_date(date, sizeof(date));
05382 fprintf(txt,
05383 ";\n"
05384 "; Message Information file\n"
05385 ";\n"
05386 "[message]\n"
05387 "origmailbox=%s\n"
05388 "context=%s\n"
05389 "macrocontext=%s\n"
05390 "exten=%s\n"
05391 "priority=%d\n"
05392 "callerchan=%s\n"
05393 "callerid=%s\n"
05394 "origdate=%s\n"
05395 "origtime=%ld\n"
05396 "category=%s\n",
05397 ext,
05398 chan->context,
05399 chan->macrocontext,
05400 chan->exten,
05401 chan->priority,
05402 chan->name,
05403 ast_callerid_merge(callerid, sizeof(callerid), S_OR(chan->cid.cid_name, NULL), S_OR(chan->cid.cid_num, NULL), "Unknown"),
05404 date, (long)time(NULL),
05405 category ? category : "");
05406 } else {
05407 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
05408 inprocess_count(vmu->mailbox, vmu->context, -1);
05409 if (ast_check_realtime("voicemail_data")) {
05410 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05411 }
05412 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05413 goto leave_vm_out;
05414 }
05415 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, NULL, options->record_gain, vms, flag);
05416
05417 if (txt) {
05418 fprintf(txt, "flag=%s\n", flag);
05419 if (duration < vmminsecs) {
05420 fclose(txt);
05421 if (option_verbose > 2)
05422 ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminsecs);
05423 ast_filedelete(tmptxtfile, NULL);
05424 unlink(tmptxtfile);
05425 if (ast_check_realtime("voicemail_data")) {
05426 snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid);
05427 ast_destroy_realtime("voicemail_data", "id", tmpid, SENTINEL);
05428 }
05429 inprocess_count(vmu->mailbox, vmu->context, -1);
05430 } else {
05431 fprintf(txt, "duration=%d\n", duration);
05432 fclose(txt);
05433 if (vm_lock_path(dir)) {
05434 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
05435
05436 ast_filedelete(tmptxtfile, NULL);
05437 unlink(tmptxtfile);
05438 inprocess_count(vmu->mailbox, vmu->context, -1);
05439 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
05440 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
05441 unlink(tmptxtfile);
05442 ast_unlock_path(dir);
05443 inprocess_count(vmu->mailbox, vmu->context, -1);
05444 if (ast_check_realtime("voicemail_data")) {
05445 snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid);
05446 ast_destroy_realtime("voicemail_data", "id", tmpid, SENTINEL);
05447 }
05448 } else {
05449 #ifndef IMAP_STORAGE
05450 msgnum = last_message_index(vmu, dir) + 1;
05451 #endif
05452 make_file(fn, sizeof(fn), dir, msgnum);
05453
05454
05455 #ifndef IMAP_STORAGE
05456 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
05457 #else
05458 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05459 #endif
05460
05461 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
05462 ast_filerename(tmptxtfile, fn, NULL);
05463 rename(tmptxtfile, txtfile);
05464 inprocess_count(vmu->mailbox, vmu->context, -1);
05465
05466
05467
05468 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
05469 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
05470
05471 ast_unlock_path(dir);
05472 if (ast_check_realtime("voicemail_data")) {
05473 snprintf(tmpid, sizeof(tmpid), "%d", rtmsgid);
05474 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
05475 ast_update_realtime("voicemail_data", "id", tmpid, "filename", fn, "duration", tmpdur, SENTINEL);
05476 }
05477
05478
05479
05480 if (ast_fileexists(fn, NULL, NULL) > 0) {
05481 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
05482 }
05483
05484
05485 while (tmpptr) {
05486 struct ast_vm_user recipu, *recip;
05487 char *exten, *cntx;
05488
05489 exten = strsep(&tmpptr, "&");
05490 cntx = strchr(exten, '@');
05491 if (cntx) {
05492 *cntx = '\0';
05493 cntx++;
05494 }
05495 if ((recip = find_user(&recipu, cntx, exten))) {
05496 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
05497 free_user(recip);
05498 }
05499 }
05500 #ifndef IMAP_STORAGE
05501 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05502
05503 char sfn[PATH_MAX];
05504 char dfn[PATH_MAX];
05505 int x;
05506
05507 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
05508 x = last_message_index(vmu, urgdir) + 1;
05509 make_file(sfn, sizeof(sfn), dir, msgnum);
05510 make_file(dfn, sizeof(dfn), urgdir, x);
05511 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
05512 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
05513
05514 ast_copy_string(fn, dfn, sizeof(fn));
05515 msgnum = x;
05516 }
05517 #endif
05518
05519 if (ast_fileexists(fn, NULL, NULL)) {
05520 #ifdef IMAP_STORAGE
05521 notify_new_message(chan, vmu, vms, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), flag);
05522 #else
05523 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), flag);
05524 #endif
05525 }
05526
05527
05528 if (ast_fileexists(fn, NULL, NULL)) {
05529 DISPOSE(dir, msgnum);
05530 }
05531 }
05532 }
05533 } else {
05534 inprocess_count(vmu->mailbox, vmu->context, -1);
05535 }
05536 if (res == '0') {
05537 goto transfer;
05538 } else if (res > 0)
05539 res = 0;
05540
05541 if (duration < vmminsecs)
05542
05543 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05544 else
05545 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05546 } else
05547 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
05548 leave_vm_out:
05549 free_user(vmu);
05550
05551 #ifdef IMAP_STORAGE
05552
05553 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n",expungeonhangup);
05554 if (expungeonhangup == 1) {
05555 ast_mutex_lock(&vms->lock);
05556 #ifdef HAVE_IMAP_TK2006
05557 if (LEVELUIDPLUS (vms->mailstream)) {
05558 mail_expunge_full(vms->mailstream,NIL,EX_UID);
05559 } else
05560 #endif
05561 mail_expunge(vms->mailstream);
05562 ast_mutex_unlock(&vms->lock);
05563 }
05564 #endif
05565
05566 ast_free(tmp);
05567 return res;
05568 }
05569
05570 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
05571 {
05572 int d;
05573 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
05574 return d;
05575 }
05576
05577 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
05578 {
05579 #ifdef IMAP_STORAGE
05580
05581
05582 char sequence[10];
05583 char mailbox[256];
05584 int res;
05585
05586
05587 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
05588
05589 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(box));
05590 ast_mutex_lock(&vms->lock);
05591
05592 if (box == OLD_FOLDER) {
05593 mail_setflag(vms->mailstream, sequence, "\\Seen");
05594 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
05595 } else if (box == NEW_FOLDER) {
05596 mail_setflag(vms->mailstream, sequence, "\\Unseen");
05597 mail_clearflag(vms->mailstream, sequence, "\\Seen");
05598 }
05599 if (!strcasecmp(mbox(NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
05600 ast_mutex_unlock(&vms->lock);
05601 return 0;
05602 }
05603
05604 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
05605 ast_debug(5, "Checking if folder exists: %s\n",mailbox);
05606 if (mail_create(vms->mailstream, mailbox) == NIL)
05607 ast_debug(5, "Folder exists.\n");
05608 else
05609 ast_log(AST_LOG_NOTICE, "Folder %s created!\n",mbox(box));
05610 res = !mail_copy(vms->mailstream, sequence, (char *)mbox(box));
05611 ast_mutex_unlock(&vms->lock);
05612 return res;
05613 #else
05614 char *dir = vms->curdir;
05615 char *username = vms->username;
05616 char *context = vmu->context;
05617 char sfn[PATH_MAX];
05618 char dfn[PATH_MAX];
05619 char ddir[PATH_MAX];
05620 const char *dbox = mbox(box);
05621 int x, i;
05622 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
05623
05624 if (vm_lock_path(ddir))
05625 return ERROR_LOCK_PATH;
05626
05627 x = last_message_index(vmu, ddir) + 1;
05628
05629 if (box == 10 && x >= vmu->maxdeletedmsg) {
05630 x--;
05631 for (i = 1; i <= x; i++) {
05632
05633 make_file(sfn, sizeof(sfn), ddir, i);
05634 make_file(dfn, sizeof(dfn), ddir, i - 1);
05635 if (EXISTS(ddir, i, sfn, NULL)) {
05636 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
05637 } else
05638 break;
05639 }
05640 } else {
05641 if (x >= vmu->maxmsg) {
05642 ast_unlock_path(ddir);
05643 return -1;
05644 }
05645 }
05646 make_file(sfn, sizeof(sfn), dir, msg);
05647 make_file(dfn, sizeof(dfn), ddir, x);
05648 if (strcmp(sfn, dfn)) {
05649 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
05650 }
05651 ast_unlock_path(ddir);
05652 #endif
05653 return 0;
05654 }
05655
05656 static int adsi_logo(unsigned char *buf)
05657 {
05658 int bytes = 0;
05659 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
05660 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
05661 return bytes;
05662 }
05663
05664 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
05665 {
05666 unsigned char buf[256];
05667 int bytes=0;
05668 int x;
05669 char num[5];
05670
05671 *useadsi = 0;
05672 bytes += ast_adsi_data_mode(buf + bytes);
05673 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05674
05675 bytes = 0;
05676 bytes += adsi_logo(buf);
05677 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
05678 #ifdef DISPLAY
05679 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
05680 #endif
05681 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05682 bytes += ast_adsi_data_mode(buf + bytes);
05683 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05684
05685 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
05686 bytes = 0;
05687 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
05688 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
05689 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05690 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05691 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05692 return 0;
05693 }
05694
05695 #ifdef DISPLAY
05696
05697 bytes = 0;
05698 bytes += ast_adsi_logo(buf);
05699 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
05700 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
05701 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05702 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05703 #endif
05704 bytes = 0;
05705 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
05706 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
05707 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
05708 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
05709 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
05710 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
05711 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
05712
05713 #ifdef DISPLAY
05714
05715 bytes = 0;
05716 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
05717 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05718
05719 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05720 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05721 #endif
05722
05723 bytes = 0;
05724
05725 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
05726 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
05727 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
05728 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
05729 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
05730 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
05731 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
05732
05733 #ifdef DISPLAY
05734
05735 bytes = 0;
05736 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
05737 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05738 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05739 #endif
05740
05741 bytes = 0;
05742 for (x=0;x<5;x++) {
05743 snprintf(num, sizeof(num), "%d", x);
05744 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
05745 }
05746 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
05747 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
05748
05749 #ifdef DISPLAY
05750
05751 bytes = 0;
05752 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
05753 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05754 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05755 #endif
05756
05757 if (ast_adsi_end_download(chan)) {
05758 bytes = 0;
05759 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
05760 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
05761 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05762 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05763 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05764 return 0;
05765 }
05766 bytes = 0;
05767 bytes += ast_adsi_download_disconnect(buf + bytes);
05768 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05769 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
05770
05771 ast_debug(1, "Done downloading scripts...\n");
05772
05773 #ifdef DISPLAY
05774
05775 bytes = 0;
05776 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
05777 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05778 #endif
05779 ast_debug(1, "Restarting session...\n");
05780
05781 bytes = 0;
05782
05783 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
05784 *useadsi = 1;
05785 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
05786 } else
05787 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
05788
05789 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05790 return 0;
05791 }
05792
05793 static void adsi_begin(struct ast_channel *chan, int *useadsi)
05794 {
05795 int x;
05796 if (!ast_adsi_available(chan))
05797 return;
05798 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
05799 if (x < 0)
05800 return;
05801 if (!x) {
05802 if (adsi_load_vmail(chan, useadsi)) {
05803 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
05804 return;
05805 }
05806 } else
05807 *useadsi = 1;
05808 }
05809
05810 static void adsi_login(struct ast_channel *chan)
05811 {
05812 unsigned char buf[256];
05813 int bytes=0;
05814 unsigned char keys[8];
05815 int x;
05816 if (!ast_adsi_available(chan))
05817 return;
05818
05819 for (x=0;x<8;x++)
05820 keys[x] = 0;
05821
05822 keys[3] = ADSI_KEY_APPS + 3;
05823
05824 bytes += adsi_logo(buf + bytes);
05825 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
05826 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
05827 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05828 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
05829 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
05830 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
05831 bytes += ast_adsi_set_keys(buf + bytes, keys);
05832 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05833 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05834 }
05835
05836 static void adsi_password(struct ast_channel *chan)
05837 {
05838 unsigned char buf[256];
05839 int bytes=0;
05840 unsigned char keys[8];
05841 int x;
05842 if (!ast_adsi_available(chan))
05843 return;
05844
05845 for (x=0;x<8;x++)
05846 keys[x] = 0;
05847
05848 keys[3] = ADSI_KEY_APPS + 3;
05849
05850 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05851 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
05852 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
05853 bytes += ast_adsi_set_keys(buf + bytes, keys);
05854 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05855 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05856 }
05857
05858 static void adsi_folders(struct ast_channel *chan, int start, char *label)
05859 {
05860 unsigned char buf[256];
05861 int bytes=0;
05862 unsigned char keys[8];
05863 int x,y;
05864
05865 if (!ast_adsi_available(chan))
05866 return;
05867
05868 for (x=0;x<5;x++) {
05869 y = ADSI_KEY_APPS + 12 + start + x;
05870 if (y > ADSI_KEY_APPS + 12 + 4)
05871 y = 0;
05872 keys[x] = ADSI_KEY_SKT | y;
05873 }
05874 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
05875 keys[6] = 0;
05876 keys[7] = 0;
05877
05878 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
05879 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
05880 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05881 bytes += ast_adsi_set_keys(buf + bytes, keys);
05882 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05883
05884 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05885 }
05886
05887 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
05888 {
05889 int bytes=0;
05890 unsigned char buf[256];
05891 char buf1[256], buf2[256];
05892 char fn2[PATH_MAX];
05893
05894 char cid[256]="";
05895 char *val;
05896 char *name, *num;
05897 char datetime[21]="";
05898 FILE *f;
05899
05900 unsigned char keys[8];
05901
05902 int x;
05903
05904 if (!ast_adsi_available(chan))
05905 return;
05906
05907
05908 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
05909 f = fopen(fn2, "r");
05910 if (f) {
05911 while (!feof(f)) {
05912 if (!fgets((char *)buf, sizeof(buf), f)) {
05913 continue;
05914 }
05915 if (!feof(f)) {
05916 char *stringp=NULL;
05917 stringp = (char *)buf;
05918 strsep(&stringp, "=");
05919 val = strsep(&stringp, "=");
05920 if (!ast_strlen_zero(val)) {
05921 if (!strcmp((char *)buf, "callerid"))
05922 ast_copy_string(cid, val, sizeof(cid));
05923 if (!strcmp((char *)buf, "origdate"))
05924 ast_copy_string(datetime, val, sizeof(datetime));
05925 }
05926 }
05927 }
05928 fclose(f);
05929 }
05930
05931 for (x=0;x<5;x++)
05932 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
05933 keys[6] = 0x0;
05934 keys[7] = 0x0;
05935
05936 if (!vms->curmsg) {
05937
05938 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05939 }
05940 if (vms->curmsg >= vms->lastmsg) {
05941
05942 if (vms->curmsg) {
05943
05944 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
05945 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05946
05947 } else {
05948
05949 keys[3] = 1;
05950 }
05951 }
05952
05953 if (!ast_strlen_zero(cid)) {
05954 ast_callerid_parse(cid, &name, &num);
05955 if (!name)
05956 name = num;
05957 } else
05958 name = "Unknown Caller";
05959
05960
05961
05962 if (vms->deleted[vms->curmsg])
05963 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
05964
05965
05966 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
05967 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
05968 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
05969 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
05970
05971 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
05972 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
05973 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
05974 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
05975 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
05976 bytes += ast_adsi_set_keys(buf + bytes, keys);
05977 bytes += ast_adsi_voice_mode(buf + bytes, 0);
05978
05979 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
05980 }
05981
05982 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
05983 {
05984 int bytes=0;
05985 unsigned char buf[256];
05986 unsigned char keys[8];
05987
05988 int x;
05989
05990 if (!ast_adsi_available(chan))
05991 return;
05992
05993
05994 for (x=0;x<5;x++)
05995 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
05996
05997 keys[6] = 0x0;
05998 keys[7] = 0x0;
05999
06000 if (!vms->curmsg) {
06001
06002 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06003 }
06004 if (vms->curmsg >= vms->lastmsg) {
06005
06006 if (vms->curmsg) {
06007
06008 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06009 } else {
06010
06011 keys[3] = 1;
06012 }
06013 }
06014
06015
06016 if (vms->deleted[vms->curmsg])
06017 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06018
06019
06020 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06021 bytes += ast_adsi_set_keys(buf + bytes, keys);
06022 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06023
06024 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06025 }
06026
06027 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06028 {
06029 unsigned char buf[256] = "";
06030 char buf1[256] = "", buf2[256] = "";
06031 int bytes=0;
06032 unsigned char keys[8];
06033 int x;
06034
06035 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06036 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06037 if (!ast_adsi_available(chan))
06038 return;
06039 if (vms->newmessages) {
06040 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06041 if (vms->oldmessages) {
06042 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06043 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06044 } else {
06045 snprintf(buf2, sizeof(buf2), "%s.", newm);
06046 }
06047 } else if (vms->oldmessages) {
06048 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06049 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06050 } else {
06051 strcpy(buf1, "You have no messages.");
06052 buf2[0] = ' ';
06053 buf2[1] = '\0';
06054 }
06055 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06056 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06057 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06058
06059 for (x=0;x<6;x++)
06060 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06061 keys[6] = 0;
06062 keys[7] = 0;
06063
06064
06065 if (vms->lastmsg < 0)
06066 keys[0] = 1;
06067 bytes += ast_adsi_set_keys(buf + bytes, keys);
06068
06069 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06070
06071 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06072 }
06073
06074 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06075 {
06076 unsigned char buf[256] = "";
06077 char buf1[256] = "", buf2[256] = "";
06078 int bytes=0;
06079 unsigned char keys[8];
06080 int x;
06081
06082 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06083
06084 if (!ast_adsi_available(chan))
06085 return;
06086
06087
06088 for (x=0;x<6;x++)
06089 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06090
06091 keys[6] = 0;
06092 keys[7] = 0;
06093
06094 if ((vms->lastmsg + 1) < 1)
06095 keys[0] = 0;
06096
06097 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06098 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06099
06100 if (vms->lastmsg + 1)
06101 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06102 else
06103 strcpy(buf2, "no messages.");
06104 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06105 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06106 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06107 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06108 bytes += ast_adsi_set_keys(buf + bytes, keys);
06109
06110 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06111
06112 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06113
06114 }
06115
06116
06117
06118
06119
06120
06121
06122
06123
06124
06125
06126
06127
06128
06129
06130 static void adsi_goodbye(struct ast_channel *chan)
06131 {
06132 unsigned char buf[256];
06133 int bytes=0;
06134
06135 if (!ast_adsi_available(chan))
06136 return;
06137 bytes += adsi_logo(buf + bytes);
06138 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06139 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06140 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06141 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06142
06143 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06144 }
06145
06146
06147
06148
06149
06150 static int get_folder(struct ast_channel *chan, int start)
06151 {
06152 int x;
06153 int d;
06154 char fn[PATH_MAX];
06155 d = ast_play_and_wait(chan, "vm-press");
06156 if (d)
06157 return d;
06158 for (x = start; x< 5; x++) {
06159 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06160 return d;
06161 d = ast_play_and_wait(chan, "vm-for");
06162 if (d)
06163 return d;
06164 snprintf(fn, sizeof(fn), "vm-%s", mbox(x));
06165 d = vm_play_folder_name(chan, fn);
06166 if (d)
06167 return d;
06168 d = ast_waitfordigit(chan, 500);
06169 if (d)
06170 return d;
06171 }
06172 d = ast_play_and_wait(chan, "vm-tocancel");
06173 if (d)
06174 return d;
06175 d = ast_waitfordigit(chan, 4000);
06176 return d;
06177 }
06178
06179
06180
06181
06182
06183
06184
06185
06186
06187
06188
06189
06190
06191 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06192 {
06193 int res = 0;
06194 int loops = 0;
06195 res = ast_play_and_wait(chan, fn);
06196 while (((res < '0') || (res > '9')) &&
06197 (res != '#') && (res >= 0) &&
06198 loops < 4) {
06199 res = get_folder(chan, 0);
06200 loops++;
06201 }
06202 if (loops == 4) {
06203 return '#';
06204 }
06205 return res;
06206 }
06207
06208
06209
06210
06211
06212
06213
06214
06215
06216
06217
06218
06219
06220
06221
06222
06223
06224
06225 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06226 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06227 {
06228 #ifdef IMAP_STORAGE
06229 int res;
06230 #endif
06231 int cmd = 0;
06232 int retries = 0, prepend_duration = 0, already_recorded = 0;
06233 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06234 char textfile[PATH_MAX];
06235 struct ast_config *msg_cfg;
06236 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06237 #ifndef IMAP_STORAGE
06238 signed char zero_gain = 0;
06239 #endif
06240 const char *duration_str;
06241
06242
06243 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06244 strcpy(textfile, msgfile);
06245 strcpy(backup, msgfile);
06246 strcpy(backup_textfile, msgfile);
06247 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06248 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06249 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06250
06251 if ((msg_cfg = ast_config_load(textfile, config_flags)) && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06252 *duration = atoi(duration_str);
06253 } else {
06254 *duration = 0;
06255 }
06256
06257 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06258 if (cmd)
06259 retries = 0;
06260 switch (cmd) {
06261 case '1':
06262
06263 #ifdef IMAP_STORAGE
06264
06265 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06266 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06267 res = ast_play_and_wait(chan, INTRO);
06268 res = ast_play_and_wait(chan, "beep");
06269 res = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *)duration, NULL, record_gain, vms, flag);
06270 cmd = 't';
06271 #else
06272
06273
06274
06275 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06276 strcpy(textfile, msgfile);
06277 strncat(textfile, ".txt", sizeof(textfile) - 1);
06278 *duration = 0;
06279
06280
06281 if (!msg_cfg) {
06282 cmd = 0;
06283 break;
06284 }
06285
06286
06287 if (already_recorded) {
06288 ast_filecopy(backup, msgfile, NULL);
06289 copy(backup_textfile, textfile);
06290 }
06291 else {
06292 ast_filecopy(msgfile, backup, NULL);
06293 copy(textfile,backup_textfile);
06294 }
06295 already_recorded = 1;
06296
06297 if (record_gain)
06298 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06299
06300 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, 1, silencethreshold, maxsilence);
06301 if (record_gain)
06302 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06303
06304
06305 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06306 *duration = atoi(duration_str);
06307
06308 if (prepend_duration) {
06309 struct ast_category *msg_cat;
06310
06311 char duration_buf[12];
06312
06313 *duration += prepend_duration;
06314 msg_cat = ast_category_get(msg_cfg, "message");
06315 snprintf(duration_buf, 11, "%ld", *duration);
06316 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06317 config_text_file_save(textfile, msg_cfg, "app_voicemail");
06318 }
06319 }
06320
06321 #endif
06322 break;
06323 case '2':
06324
06325 #ifdef IMAP_STORAGE
06326 *vms->introfn = '\0';
06327 #endif
06328 cmd = 't';
06329 break;
06330 case '*':
06331 cmd = '*';
06332 break;
06333 default:
06334 cmd = ast_play_and_wait(chan,"vm-forwardoptions");
06335
06336 if (!cmd)
06337 cmd = ast_play_and_wait(chan,"vm-starmain");
06338
06339 if (!cmd)
06340 cmd = ast_waitfordigit(chan,6000);
06341 if (!cmd)
06342 retries++;
06343 if (retries > 3)
06344 cmd = 't';
06345 }
06346 }
06347
06348 if (msg_cfg)
06349 ast_config_destroy(msg_cfg);
06350 if (prepend_duration)
06351 *duration = prepend_duration;
06352
06353 if (already_recorded && cmd == -1) {
06354
06355 ast_filerename(backup, msgfile, NULL);
06356 rename(backup_textfile, textfile);
06357 }
06358
06359 if (cmd == 't' || cmd == 'S')
06360 cmd = 0;
06361 return cmd;
06362 }
06363
06364 static void queue_mwi_event(const char *box, int urgent, int new, int old)
06365 {
06366 struct ast_event *event;
06367 char *mailbox, *context;
06368
06369
06370 context = mailbox = ast_strdupa(box);
06371 strsep(&context, "@");
06372 if (ast_strlen_zero(context))
06373 context = "default";
06374
06375 if (!(event = ast_event_new(AST_EVENT_MWI,
06376 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
06377 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
06378 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
06379 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
06380 AST_EVENT_IE_END))) {
06381 return;
06382 }
06383
06384 ast_event_queue_and_cache(event);
06385 }
06386
06387
06388
06389
06390
06391
06392
06393
06394
06395
06396
06397
06398
06399
06400 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag)
06401 {
06402 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
06403 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
06404 const char *category;
06405 char *myserveremail = serveremail;
06406
06407 ast_channel_lock(chan);
06408 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
06409 category = ast_strdupa(category);
06410 }
06411 ast_channel_unlock(chan);
06412
06413 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
06414 make_file(fn, sizeof(fn), todir, msgnum);
06415 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
06416
06417 if (!ast_strlen_zero(vmu->attachfmt)) {
06418 if (strstr(fmt, vmu->attachfmt))
06419 fmt = vmu->attachfmt;
06420 else
06421 ast_log(AST_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);
06422 }
06423
06424
06425 fmt = ast_strdupa(fmt);
06426 stringp = fmt;
06427 strsep(&stringp, "|");
06428
06429 if (!ast_strlen_zero(vmu->serveremail))
06430 myserveremail = vmu->serveremail;
06431
06432 if (!ast_strlen_zero(vmu->email)) {
06433 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
06434
06435 if (attach_user_voicemail)
06436 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
06437
06438
06439 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
06440
06441 if (attach_user_voicemail)
06442 DISPOSE(todir, msgnum);
06443 }
06444
06445 if (!ast_strlen_zero(vmu->pager)) {
06446 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(0), cidnum, cidname, duration, vmu, category, flag);
06447 }
06448
06449 if (ast_test_flag(vmu, VM_DELETE))
06450 DELETE(todir, msgnum, fn, vmu);
06451
06452
06453 if (ast_app_has_voicemail(ext_context, NULL))
06454 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
06455
06456 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
06457
06458 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);
06459 run_externnotify(vmu->context, vmu->mailbox, flag);
06460
06461 #ifdef IMAP_STORAGE
06462 vm_delete(fn);
06463 if (ast_test_flag(vmu, VM_DELETE)) {
06464 vm_imap_delete(NULL, vms->curmsg, vmu);
06465 vms->newmessages--;
06466 }
06467 #endif
06468
06469 return 0;
06470 }
06471
06472
06473
06474
06475
06476
06477
06478
06479
06480
06481
06482
06483
06484
06485
06486
06487
06488
06489
06490
06491
06492
06493
06494
06495
06496
06497
06498 static int forward_message(struct ast_channel *chan, char *context, struct vm_state *vms, struct ast_vm_user *sender, char *fmt, int is_new_message, signed char record_gain, int urgent)
06499 {
06500 #ifdef IMAP_STORAGE
06501 int todircount=0;
06502 struct vm_state *dstvms;
06503 #endif
06504 char username[70]="";
06505 char fn[PATH_MAX];
06506 char ecodes[16] = "#";
06507 int res = 0, cmd = 0;
06508 struct ast_vm_user *receiver = NULL, *vmtmp;
06509 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
06510 char *stringp;
06511 const char *s;
06512 int saved_messages = 0, found = 0;
06513 int valid_extensions = 0;
06514 char *dir;
06515 int curmsg;
06516 char urgent_str[7] = "";
06517 char tmptxtfile[PATH_MAX];
06518 int prompt_played = 0;
06519 #ifndef IMAP_STORAGE
06520 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06521 #endif
06522 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
06523 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
06524 }
06525
06526 if (vms == NULL) return -1;
06527 dir = vms->curdir;
06528 curmsg = vms->curmsg;
06529
06530 tmptxtfile[0] = '\0';
06531 while (!res && !valid_extensions) {
06532 int use_directory = 0;
06533 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
06534 int done = 0;
06535 int retries = 0;
06536 cmd=0;
06537 while ((cmd >= 0) && !done ){
06538 if (cmd)
06539 retries = 0;
06540 switch (cmd) {
06541 case '1':
06542 use_directory = 0;
06543 done = 1;
06544 break;
06545 case '2':
06546 use_directory = 1;
06547 done=1;
06548 break;
06549 case '*':
06550 cmd = 't';
06551 done = 1;
06552 break;
06553 default:
06554
06555 cmd = ast_play_and_wait(chan,"vm-forward");
06556 if (!cmd)
06557 cmd = ast_waitfordigit(chan,3000);
06558 if (!cmd)
06559 retries++;
06560 if (retries > 3) {
06561 cmd = 't';
06562 done = 1;
06563 }
06564
06565 }
06566 }
06567 if (cmd < 0 || cmd == 't')
06568 break;
06569 }
06570
06571 if (use_directory) {
06572
06573
06574 char old_context[sizeof(chan->context)];
06575 char old_exten[sizeof(chan->exten)];
06576 int old_priority;
06577 struct ast_app* directory_app;
06578
06579 directory_app = pbx_findapp("Directory");
06580 if (directory_app) {
06581 char vmcontext[256];
06582
06583 memcpy(old_context, chan->context, sizeof(chan->context));
06584 memcpy(old_exten, chan->exten, sizeof(chan->exten));
06585 old_priority = chan->priority;
06586
06587
06588 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
06589 res = pbx_exec(chan, directory_app, vmcontext);
06590
06591 ast_copy_string(username, chan->exten, sizeof(username));
06592
06593
06594 memcpy(chan->context, old_context, sizeof(chan->context));
06595 memcpy(chan->exten, old_exten, sizeof(chan->exten));
06596 chan->priority = old_priority;
06597 } else {
06598 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
06599 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
06600 }
06601 } else {
06602
06603 res = ast_streamfile(chan, "vm-extension", chan->language);
06604 prompt_played++;
06605 if (res || prompt_played > 4)
06606 break;
06607 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
06608 break;
06609 }
06610
06611
06612 if (ast_strlen_zero(username))
06613 continue;
06614 stringp = username;
06615 s = strsep(&stringp, "*");
06616
06617 valid_extensions = 1;
06618 while (s) {
06619 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
06620 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
06621 found++;
06622 } else {
06623
06624
06625
06626
06627
06628 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
06629 free_user(receiver);
06630 }
06631 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
06632 valid_extensions = 0;
06633 break;
06634 }
06635
06636
06637 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
06638 RETRIEVE(fn, -1, s, receiver->context);
06639 if (ast_fileexists(fn, NULL, NULL) > 0) {
06640 res = ast_stream_and_wait(chan, fn, ecodes);
06641 if (res) {
06642 DISPOSE(fn, -1);
06643 return res;
06644 }
06645 } else {
06646 res = ast_say_digit_str(chan, s, ecodes, chan->language);
06647 }
06648 DISPOSE(fn, -1);
06649
06650 s = strsep(&stringp, "*");
06651 }
06652
06653 if (valid_extensions)
06654 break;
06655
06656 res = ast_play_and_wait(chan, "pbx-invalid");
06657 }
06658
06659 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
06660 return res;
06661 if (is_new_message == 1) {
06662 struct leave_vm_options leave_options;
06663 char mailbox[AST_MAX_EXTENSION * 2 + 2];
06664 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
06665
06666
06667 memset(&leave_options, 0, sizeof(leave_options));
06668 leave_options.record_gain = record_gain;
06669 cmd = leave_voicemail(chan, mailbox, &leave_options);
06670 } else {
06671
06672 long duration = 0;
06673 struct vm_state vmstmp;
06674 int copy_msg_result = 0;
06675 memcpy(&vmstmp, vms, sizeof(vmstmp));
06676
06677 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
06678
06679 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
06680 if (!cmd) {
06681 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
06682 #ifdef IMAP_STORAGE
06683 int attach_user_voicemail;
06684 char *myserveremail = serveremail;
06685
06686
06687 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
06688 if (!dstvms) {
06689 dstvms = create_vm_state_from_user(vmtmp);
06690 }
06691 if (dstvms) {
06692 init_mailstream(dstvms, 0);
06693 if (!dstvms->mailstream) {
06694 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
06695 } else {
06696 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
06697 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
06698 }
06699 } else {
06700 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
06701 }
06702 if (!ast_strlen_zero(vmtmp->serveremail))
06703 myserveremail = vmtmp->serveremail;
06704 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
06705
06706 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox, dstvms->curbox, S_OR(chan->cid.cid_num, NULL), S_OR(chan->cid.cid_name, NULL), vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan, NULL, urgent_str);
06707 #else
06708 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
06709 #endif
06710 saved_messages++;
06711 AST_LIST_REMOVE_CURRENT(list);
06712 free_user(vmtmp);
06713 if (res)
06714 break;
06715 }
06716 AST_LIST_TRAVERSE_SAFE_END;
06717 if (saved_messages > 0 && !copy_msg_result) {
06718
06719
06720
06721
06722
06723
06724
06725
06726 #ifdef IMAP_STORAGE
06727
06728 if (ast_strlen_zero(vmstmp.introfn))
06729 #endif
06730 res = ast_play_and_wait(chan, "vm-msgsaved");
06731 }
06732 #ifndef IMAP_STORAGE
06733 else {
06734
06735 res = ast_play_and_wait(chan, "vm-mailboxfull");
06736 }
06737
06738 make_file(msgfile, sizeof(msgfile), dir, curmsg);
06739 strcpy(textfile, msgfile);
06740 strcpy(backup, msgfile);
06741 strcpy(backup_textfile, msgfile);
06742 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06743 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06744 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06745 if (ast_fileexists(backup, NULL, NULL) > 0) {
06746 ast_filerename(backup, msgfile, NULL);
06747 rename(backup_textfile, textfile);
06748 }
06749 #endif
06750 }
06751 DISPOSE(dir, curmsg);
06752 }
06753
06754
06755 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list)))
06756 free_user(vmtmp);
06757 return res ? res : cmd;
06758 }
06759
06760 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
06761 {
06762 int res;
06763 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
06764 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
06765 return res;
06766 }
06767
06768 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
06769 {
06770 return ast_control_streamfile(chan, file, listen_control_forward_key, listen_control_reverse_key, listen_control_stop_key, listen_control_pause_key, listen_control_restart_key, skipms, NULL);
06771 }
06772
06773 static int play_message_category(struct ast_channel *chan, const char *category)
06774 {
06775 int res = 0;
06776
06777 if (!ast_strlen_zero(category))
06778 res = ast_play_and_wait(chan, category);
06779
06780 if (res) {
06781 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
06782 res = 0;
06783 }
06784
06785 return res;
06786 }
06787
06788 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
06789 {
06790 int res = 0;
06791 struct vm_zone *the_zone = NULL;
06792 time_t t;
06793
06794 if (ast_get_time_t(origtime, &t, 0, NULL)) {
06795 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
06796 return 0;
06797 }
06798
06799
06800 if (!ast_strlen_zero(vmu->zonetag)) {
06801
06802 struct vm_zone *z;
06803 AST_LIST_LOCK(&zones);
06804 AST_LIST_TRAVERSE(&zones, z, list) {
06805 if (!strcmp(z->name, vmu->zonetag)) {
06806 the_zone = z;
06807 break;
06808 }
06809 }
06810 AST_LIST_UNLOCK(&zones);
06811 }
06812
06813
06814 #if 0
06815
06816 ast_localtime(&t, &time_now, NULL);
06817 tv_now = ast_tvnow();
06818 ast_localtime(&tv_now, &time_then, NULL);
06819
06820
06821 if (time_now.tm_year == time_then.tm_year)
06822 snprintf(temp,sizeof(temp),"%d",time_now.tm_yday);
06823 else
06824 snprintf(temp,sizeof(temp),"%d",(time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
06825 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
06826
06827
06828 #endif
06829 if (the_zone) {
06830 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
06831 } else if (!strncasecmp(chan->language, "de", 2)) {
06832 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
06833 } else if (!strncasecmp(chan->language, "gr", 2)) {
06834 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
06835 } else if (!strncasecmp(chan->language, "it", 2)) {
06836 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);
06837 } else if (!strncasecmp(chan->language, "nl", 2)) {
06838 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
06839 } else if (!strncasecmp(chan->language, "no", 2)) {
06840 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
06841 } else if (!strncasecmp(chan->language, "pl", 2)) {
06842 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
06843 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
06844 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);
06845 } else if (!strncasecmp(chan->language, "se", 2)) {
06846 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
06847 } else if (!strncasecmp(chan->language, "zh", 2)) {
06848 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
06849 } else {
06850 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
06851 }
06852 #if 0
06853 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
06854 #endif
06855 return res;
06856 }
06857
06858
06859
06860 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
06861 {
06862 int res = 0;
06863 int i;
06864 char *callerid, *name;
06865 char prefile[PATH_MAX] = "";
06866
06867
06868
06869
06870
06871
06872
06873
06874
06875 if ((cid == NULL)||(context == NULL))
06876 return res;
06877
06878
06879 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
06880 ast_callerid_parse(cid, &name, &callerid);
06881 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
06882
06883
06884 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
06885 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
06886 if ((strcmp(cidinternalcontexts[i], context) == 0))
06887 break;
06888 }
06889 if (i != MAX_NUM_CID_CONTEXTS){
06890 if (!res) {
06891 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
06892 if (!ast_strlen_zero(prefile)) {
06893
06894 if (ast_fileexists(prefile, NULL, NULL) > 0) {
06895 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
06896 if (!callback)
06897 res = wait_file2(chan, vms, "vm-from");
06898 res = ast_stream_and_wait(chan, prefile, "");
06899 } else {
06900 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
06901
06902 if (!callback)
06903 res = wait_file2(chan, vms, "vm-from-extension");
06904 res = ast_say_digit_str(chan, callerid, "", chan->language);
06905 }
06906 }
06907 }
06908 } else if (!res) {
06909 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
06910
06911 if (!callback)
06912 res = wait_file2(chan, vms, "vm-from-phonenumber");
06913 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
06914 }
06915 } else {
06916
06917 ast_debug(1, "VM-CID: From an unknown number\n");
06918
06919 res = wait_file2(chan, vms, "vm-unknown-caller");
06920 }
06921 return res;
06922 }
06923
06924 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
06925 {
06926 int res = 0;
06927 int durationm;
06928 int durations;
06929
06930 if (duration == NULL)
06931 return res;
06932
06933
06934 durations=atoi(duration);
06935 durationm=(durations / 60);
06936
06937 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
06938
06939 if ((!res) && (durationm >= minduration)) {
06940 res = wait_file2(chan, vms, "vm-duration");
06941
06942
06943 if (!strncasecmp(chan->language, "pl", 2)) {
06944 div_t num = div(durationm, 10);
06945
06946 if (durationm == 1) {
06947 res = ast_play_and_wait(chan, "digits/1z");
06948 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
06949 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
06950 if (num.rem == 2) {
06951 if (!num.quot) {
06952 res = ast_play_and_wait(chan, "digits/2-ie");
06953 } else {
06954 res = say_and_wait(chan, durationm - 2 , chan->language);
06955 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
06956 }
06957 } else {
06958 res = say_and_wait(chan, durationm, chan->language);
06959 }
06960 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
06961 } else {
06962 res = say_and_wait(chan, durationm, chan->language);
06963 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
06964 }
06965
06966 } else {
06967 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
06968 res = wait_file2(chan, vms, "vm-minutes");
06969 }
06970 }
06971 return res;
06972 }
06973
06974 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
06975 {
06976 int res = 0;
06977 char filename[256], *cid;
06978 const char *origtime, *context, *category, *duration, *flag;
06979 struct ast_config *msg_cfg;
06980 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06981
06982 vms->starting = 0;
06983 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
06984 adsi_message(chan, vms);
06985 if (!vms->curmsg)
06986 res = wait_file2(chan, vms, "vm-first");
06987 else if (vms->curmsg == vms->lastmsg)
06988 res = wait_file2(chan, vms, "vm-last");
06989
06990 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
06991 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
06992 msg_cfg = ast_config_load(filename, config_flags);
06993 if (!msg_cfg) {
06994 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
06995 return 0;
06996 }
06997 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
06998
06999
07000 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07001 res = wait_file2(chan, vms, "vm-Urgent");
07002 }
07003
07004 if (!res) {
07005
07006 if (!strncasecmp(chan->language, "pl", 2)) {
07007 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07008 int ten, one;
07009 char nextmsg[256];
07010 ten = (vms->curmsg + 1) / 10;
07011 one = (vms->curmsg + 1) % 10;
07012
07013 if (vms->curmsg < 20) {
07014 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07015 res = wait_file2(chan, vms, nextmsg);
07016 } else {
07017 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07018 res = wait_file2(chan, vms, nextmsg);
07019 if (one > 0) {
07020 if (!res) {
07021 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07022 res = wait_file2(chan, vms, nextmsg);
07023 }
07024 }
07025 }
07026 }
07027 if (!res)
07028 res = wait_file2(chan, vms, "vm-message");
07029
07030 } else if (!strncasecmp(chan->language, "he", 2)) {
07031 if (!vms->curmsg) {
07032 res = wait_file2(chan, vms, "vm-message");
07033 res = wait_file2(chan, vms, "vm-first");
07034 } else if (vms->curmsg == vms->lastmsg) {
07035 res = wait_file2(chan, vms, "vm-message");
07036 res = wait_file2(chan, vms, "vm-last");
07037 } else {
07038 res = wait_file2(chan, vms, "vm-message");
07039 res = wait_file2(chan, vms, "vm-number");
07040 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07041 }
07042 } else {
07043 if (!strncasecmp(chan->language, "se", 2)) {
07044 res = wait_file2(chan, vms, "vm-meddelandet");
07045 } else {
07046 res = wait_file2(chan, vms, "vm-message");
07047 }
07048 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07049 if (!res) {
07050 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07051 }
07052 }
07053 }
07054 }
07055
07056 if (!msg_cfg) {
07057 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07058 return 0;
07059 }
07060
07061 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07062 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07063 DISPOSE(vms->curdir, vms->curmsg);
07064 ast_config_destroy(msg_cfg);
07065 return 0;
07066 }
07067
07068 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07069 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07070 category = ast_variable_retrieve(msg_cfg, "message", "category");
07071
07072 context = ast_variable_retrieve(msg_cfg, "message", "context");
07073 if (!strncasecmp("macro",context,5))
07074 context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
07075 if (!res) {
07076 res = play_message_category(chan, category);
07077 }
07078 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE)))
07079 res = play_message_datetime(chan, vmu, origtime, filename);
07080 if ((!res) && (ast_test_flag(vmu, VM_SAYCID)))
07081 res = play_message_callerid(chan, vms, cid, context, 0);
07082 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION)))
07083 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07084
07085 if (res == '1')
07086 res = 0;
07087 ast_config_destroy(msg_cfg);
07088
07089 if (!res) {
07090 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07091 vms->heard[vms->curmsg] = 1;
07092 #ifdef IMAP_STORAGE
07093
07094
07095
07096 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07097 wait_file(chan, vms, vms->introfn);
07098 }
07099 #endif
07100 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07101 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07102 res = 0;
07103 }
07104 }
07105 DISPOSE(vms->curdir, vms->curmsg);
07106 return res;
07107 }
07108
07109 #ifdef IMAP_STORAGE
07110 static int imap_remove_file(char *dir, int msgnum)
07111 {
07112 char fn[PATH_MAX];
07113 char full_fn[PATH_MAX];
07114 char intro[PATH_MAX] = {0,};
07115
07116 if (msgnum > -1) {
07117 make_file(fn, sizeof(fn), dir, msgnum);
07118 snprintf(intro, sizeof(intro), "%sintro", fn);
07119 } else
07120 ast_copy_string(fn, dir, sizeof(fn));
07121
07122 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07123 ast_filedelete(fn, NULL);
07124 if (!ast_strlen_zero(intro)) {
07125 ast_filedelete(intro, NULL);
07126 }
07127 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07128 unlink(full_fn);
07129 }
07130 return 0;
07131 }
07132
07133
07134
07135 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07136 {
07137 char *file, *filename;
07138 char *attachment;
07139 char arg[10];
07140 int i;
07141 BODY* body;
07142
07143
07144 file = strrchr(ast_strdupa(dir), '/');
07145 if (file)
07146 *file++ = '\0';
07147 else {
07148 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07149 return -1;
07150 }
07151
07152 ast_mutex_lock(&vms->lock);
07153 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07154 mail_fetchstructure(vms->mailstream, i + 1, &body);
07155
07156 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07157 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07158 } else {
07159 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07160 ast_mutex_unlock(&vms->lock);
07161 return -1;
07162 }
07163 filename = strsep(&attachment, ".");
07164 if (!strcmp(filename, file)) {
07165 sprintf (arg,"%d", i+1);
07166 mail_setflag (vms->mailstream,arg,"\\DELETED");
07167 }
07168 }
07169 mail_expunge(vms->mailstream);
07170 ast_mutex_unlock(&vms->lock);
07171 return 0;
07172 }
07173
07174 #else
07175 #ifndef IMAP_STORAGE
07176 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07177 {
07178 int count_msg, last_msg;
07179
07180 ast_copy_string(vms->curbox, mbox(box), sizeof(vms->curbox));
07181
07182
07183
07184
07185 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07186
07187
07188 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07189
07190 count_msg = count_messages(vmu, vms->curdir);
07191 if (count_msg < 0)
07192 return count_msg;
07193 else
07194 vms->lastmsg = count_msg - 1;
07195
07196
07197
07198
07199
07200
07201
07202
07203 if (vm_lock_path(vms->curdir)) {
07204 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07205 return -1;
07206 }
07207
07208 last_msg = last_message_index(vmu, vms->curdir);
07209 ast_unlock_path(vms->curdir);
07210
07211 if (last_msg < 0)
07212 return last_msg;
07213
07214 return 0;
07215 }
07216 #endif
07217 #endif
07218
07219 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
07220 {
07221 int x = 0;
07222 #ifndef IMAP_STORAGE
07223 int res = 0, nummsg;
07224 char fn2[PATH_MAX];
07225 #endif
07226
07227 if (vms->lastmsg <= -1)
07228 goto done;
07229
07230 vms->curmsg = -1;
07231 #ifndef IMAP_STORAGE
07232
07233 if (vm_lock_path(vms->curdir))
07234 return ERROR_LOCK_PATH;
07235
07236 for (x = 0; x < vmu->maxmsg; x++) {
07237 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
07238
07239 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07240 if (!EXISTS(vms->curdir, x, vms->fn, NULL))
07241 break;
07242 vms->curmsg++;
07243 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
07244 if (strcmp(vms->fn, fn2)) {
07245 RENAME(vms->curdir, x, vmu->mailbox,vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
07246 }
07247 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
07248
07249 res = save_to_folder(vmu, vms, x, 1);
07250 if (res == ERROR_LOCK_PATH) {
07251
07252 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
07253 vms->deleted[x] = 0;
07254 vms->heard[x] = 0;
07255 --x;
07256 }
07257 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
07258
07259 res = save_to_folder(vmu, vms, x, 10);
07260 if (res == ERROR_LOCK_PATH) {
07261
07262 vms->deleted[x] = 0;
07263 vms->heard[x] = 0;
07264 --x;
07265 }
07266 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
07267
07268
07269 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07270 if (EXISTS(vms->curdir, x, vms->fn, NULL))
07271 DELETE(vms->curdir, x, vms->fn, vmu);
07272 }
07273 }
07274
07275
07276 nummsg = x - 1;
07277 for (x = vms->curmsg + 1; x <= nummsg; x++) {
07278 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07279 if (EXISTS(vms->curdir, x, vms->fn, NULL))
07280 DELETE(vms->curdir, x, vms->fn, vmu);
07281 }
07282 ast_unlock_path(vms->curdir);
07283 #else
07284 if (vms->deleted) {
07285 for (x=0;x < vmu->maxmsg;x++) {
07286 if (vms->deleted[x]) {
07287 ast_debug(3,"IMAP delete of %d\n",x);
07288 DELETE(vms->curdir, x, vms->fn, vmu);
07289 }
07290 }
07291 }
07292 #endif
07293
07294 done:
07295 if (vms->deleted)
07296 memset(vms->deleted, 0, vmu->maxmsg * sizeof(int));
07297 if (vms->heard)
07298 memset(vms->heard, 0, vmu->maxmsg * sizeof(int));
07299
07300 return 0;
07301 }
07302
07303
07304
07305
07306
07307
07308
07309 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
07310 {
07311 int cmd;
07312 char *buf;
07313
07314 buf = alloca(strlen(box)+2);
07315 strcpy(buf, box);
07316 strcat(buf,"s");
07317
07318 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
07319 cmd = ast_play_and_wait(chan, buf);
07320 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07321 } else {
07322 cmd = ast_play_and_wait(chan, "vm-messages");
07323 return cmd ? cmd : ast_play_and_wait(chan, box);
07324 }
07325 }
07326
07327 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
07328 {
07329 int cmd;
07330
07331 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
07332 if (!strcasecmp(box, "vm-INBOX"))
07333 cmd = ast_play_and_wait(chan, "vm-new-e");
07334 else
07335 cmd = ast_play_and_wait(chan, "vm-old-e");
07336 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07337 } else {
07338 cmd = ast_play_and_wait(chan, "vm-messages");
07339 return cmd ? cmd : ast_play_and_wait(chan, box);
07340 }
07341 }
07342
07343 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
07344 {
07345 int cmd;
07346
07347 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
07348 cmd = ast_play_and_wait(chan, "vm-messages");
07349 return cmd ? cmd : ast_play_and_wait(chan, box);
07350 } else {
07351 cmd = ast_play_and_wait(chan, box);
07352 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07353 }
07354 }
07355
07356 static int vm_play_folder_name(struct ast_channel *chan, char *box)
07357 {
07358 int cmd;
07359
07360 if ( !strncasecmp(chan->language, "it", 2) ||
07361 !strncasecmp(chan->language, "es", 2) ||
07362 !strncasecmp(chan->language, "pt", 2)) {
07363 cmd = ast_play_and_wait(chan, "vm-messages");
07364 return cmd ? cmd : ast_play_and_wait(chan, box);
07365 } else if (!strncasecmp(chan->language, "gr", 2)) {
07366 return vm_play_folder_name_gr(chan, box);
07367 } else if (!strncasecmp(chan->language, "he", 2)) {
07368 return ast_play_and_wait(chan, box);
07369 } else if (!strncasecmp(chan->language, "pl", 2)) {
07370 return vm_play_folder_name_pl(chan, box);
07371 } else if (!strncasecmp(chan->language, "ua", 2)) {
07372 return vm_play_folder_name_ua(chan, box);
07373 } else {
07374 cmd = ast_play_and_wait(chan, box);
07375 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
07376 }
07377 }
07378
07379
07380
07381
07382
07383
07384
07385
07386
07387
07388
07389
07390
07391 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
07392 {
07393 int res = 0;
07394
07395 if (vms->newmessages) {
07396 res = ast_play_and_wait(chan, "vm-youhave");
07397 if (!res)
07398 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
07399 if (!res) {
07400 if ((vms->newmessages == 1)) {
07401 res = ast_play_and_wait(chan, "vm-INBOX");
07402 if (!res)
07403 res = ast_play_and_wait(chan, "vm-message");
07404 } else {
07405 res = ast_play_and_wait(chan, "vm-INBOXs");
07406 if (!res)
07407 res = ast_play_and_wait(chan, "vm-messages");
07408 }
07409 }
07410 } else if (vms->oldmessages){
07411 res = ast_play_and_wait(chan, "vm-youhave");
07412 if (!res)
07413 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
07414 if ((vms->oldmessages == 1)){
07415 res = ast_play_and_wait(chan, "vm-Old");
07416 if (!res)
07417 res = ast_play_and_wait(chan, "vm-message");
07418 } else {
07419 res = ast_play_and_wait(chan, "vm-Olds");
07420 if (!res)
07421 res = ast_play_and_wait(chan, "vm-messages");
07422 }
07423 } else if (!vms->oldmessages && !vms->newmessages)
07424 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
07425 return res;
07426 }
07427
07428
07429
07430
07431
07432
07433
07434
07435
07436
07437
07438
07439
07440
07441
07442
07443
07444
07445
07446
07447
07448
07449
07450
07451
07452
07453
07454
07455
07456
07457
07458
07459
07460
07461
07462
07463
07464
07465
07466
07467
07468
07469
07470
07471
07472
07473
07474
07475
07476
07477
07478
07479
07480
07481
07482
07483
07484
07485 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
07486 {
07487 int res;
07488 int lastnum = 0;
07489
07490 res = ast_play_and_wait(chan, "vm-youhave");
07491
07492 if (!res && vms->newmessages) {
07493 lastnum = vms->newmessages;
07494
07495 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
07496 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
07497 }
07498
07499 if (!res && vms->oldmessages) {
07500 res = ast_play_and_wait(chan, "vm-and");
07501 }
07502 }
07503
07504 if (!res && vms->oldmessages) {
07505 lastnum = vms->oldmessages;
07506
07507 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
07508 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
07509 }
07510 }
07511
07512 if (!res) {
07513 if (lastnum == 0) {
07514 res = ast_play_and_wait(chan, "vm-no");
07515 }
07516 if (!res) {
07517 res = ast_say_counted_noun(chan, lastnum, "vm-message");
07518 }
07519 }
07520
07521 return res;
07522 }
07523
07524
07525 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
07526 {
07527 int res = 0;
07528
07529
07530 if (!res) {
07531 if ((vms->newmessages) || (vms->oldmessages)) {
07532 res = ast_play_and_wait(chan, "vm-youhave");
07533 }
07534
07535
07536
07537
07538
07539 if (vms->newmessages) {
07540 if (!res) {
07541 if (vms->newmessages == 1) {
07542 res = ast_play_and_wait(chan, "vm-INBOX1");
07543 } else {
07544 if (vms->newmessages == 2) {
07545 res = ast_play_and_wait(chan, "vm-shtei");
07546 } else {
07547 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
07548 }
07549 res = ast_play_and_wait(chan, "vm-INBOX");
07550 }
07551 }
07552 if (vms->oldmessages && !res) {
07553 res = ast_play_and_wait(chan, "vm-and");
07554 if (vms->oldmessages == 1) {
07555 res = ast_play_and_wait(chan, "vm-Old1");
07556 } else {
07557 if (vms->oldmessages == 2) {
07558 res = ast_play_and_wait(chan, "vm-shtei");
07559 } else {
07560 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
07561 }
07562 res = ast_play_and_wait(chan, "vm-Old");
07563 }
07564 }
07565 }
07566 if (!res && vms->oldmessages && !vms->newmessages) {
07567 if (!res) {
07568 if (vms->oldmessages == 1) {
07569 res = ast_play_and_wait(chan, "vm-Old1");
07570 } else {
07571 if (vms->oldmessages == 2) {
07572 res = ast_play_and_wait(chan, "vm-shtei");
07573 } else {
07574 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
07575 }
07576 res = ast_play_and_wait(chan, "vm-Old");
07577 }
07578 }
07579 }
07580 if (!res) {
07581 if (!vms->oldmessages && !vms->newmessages) {
07582 if (!res) {
07583 res = ast_play_and_wait(chan, "vm-nomessages");
07584 }
07585 }
07586 }
07587 }
07588 return res;
07589 }
07590
07591
07592 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
07593 {
07594 int res;
07595
07596
07597 res = ast_play_and_wait(chan, "vm-youhave");
07598 if (!res) {
07599 if (vms->urgentmessages) {
07600 res = say_and_wait(chan, vms->urgentmessages, chan->language);
07601 if (!res)
07602 res = ast_play_and_wait(chan, "vm-Urgent");
07603 if ((vms->oldmessages || vms->newmessages) && !res) {
07604 res = ast_play_and_wait(chan, "vm-and");
07605 } else if (!res) {
07606 if ((vms->urgentmessages == 1))
07607 res = ast_play_and_wait(chan, "vm-message");
07608 else
07609 res = ast_play_and_wait(chan, "vm-messages");
07610 }
07611 }
07612 if (vms->newmessages) {
07613 res = say_and_wait(chan, vms->newmessages, chan->language);
07614 if (!res)
07615 res = ast_play_and_wait(chan, "vm-INBOX");
07616 if (vms->oldmessages && !res)
07617 res = ast_play_and_wait(chan, "vm-and");
07618 else if (!res) {
07619 if ((vms->newmessages == 1))
07620 res = ast_play_and_wait(chan, "vm-message");
07621 else
07622 res = ast_play_and_wait(chan, "vm-messages");
07623 }
07624
07625 }
07626 if (!res && vms->oldmessages) {
07627 res = say_and_wait(chan, vms->oldmessages, chan->language);
07628 if (!res)
07629 res = ast_play_and_wait(chan, "vm-Old");
07630 if (!res) {
07631 if (vms->oldmessages == 1)
07632 res = ast_play_and_wait(chan, "vm-message");
07633 else
07634 res = ast_play_and_wait(chan, "vm-messages");
07635 }
07636 }
07637 if (!res) {
07638 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
07639 res = ast_play_and_wait(chan, "vm-no");
07640 if (!res)
07641 res = ast_play_and_wait(chan, "vm-messages");
07642 }
07643 }
07644 }
07645 return res;
07646 }
07647
07648
07649 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
07650 {
07651
07652 int res;
07653 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
07654 res = ast_play_and_wait(chan, "vm-no") ||
07655 ast_play_and_wait(chan, "vm-message");
07656 else
07657 res = ast_play_and_wait(chan, "vm-youhave");
07658 if (!res && vms->newmessages) {
07659 res = (vms->newmessages == 1) ?
07660 ast_play_and_wait(chan, "digits/un") ||
07661 ast_play_and_wait(chan, "vm-nuovo") ||
07662 ast_play_and_wait(chan, "vm-message") :
07663
07664 say_and_wait(chan, vms->newmessages, chan->language) ||
07665 ast_play_and_wait(chan, "vm-nuovi") ||
07666 ast_play_and_wait(chan, "vm-messages");
07667 if (!res && vms->oldmessages)
07668 res = ast_play_and_wait(chan, "vm-and");
07669 }
07670 if (!res && vms->oldmessages) {
07671 res = (vms->oldmessages == 1) ?
07672 ast_play_and_wait(chan, "digits/un") ||
07673 ast_play_and_wait(chan, "vm-vecchio") ||
07674 ast_play_and_wait(chan, "vm-message") :
07675
07676 say_and_wait(chan, vms->oldmessages, chan->language) ||
07677 ast_play_and_wait(chan, "vm-vecchi") ||
07678 ast_play_and_wait(chan, "vm-messages");
07679 }
07680 return res;
07681 }
07682
07683
07684 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
07685 {
07686
07687 int res;
07688 div_t num;
07689
07690 if (!vms->oldmessages && !vms->newmessages) {
07691 res = ast_play_and_wait(chan, "vm-no");
07692 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07693 return res;
07694 } else {
07695 res = ast_play_and_wait(chan, "vm-youhave");
07696 }
07697
07698 if (vms->newmessages) {
07699 num = div(vms->newmessages, 10);
07700 if (vms->newmessages == 1) {
07701 res = ast_play_and_wait(chan, "digits/1-a");
07702 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
07703 res = res ? res : ast_play_and_wait(chan, "vm-message");
07704 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07705 if (num.rem == 2) {
07706 if (!num.quot) {
07707 res = ast_play_and_wait(chan, "digits/2-ie");
07708 } else {
07709 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
07710 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07711 }
07712 } else {
07713 res = say_and_wait(chan, vms->newmessages, chan->language);
07714 }
07715 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
07716 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07717 } else {
07718 res = say_and_wait(chan, vms->newmessages, chan->language);
07719 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
07720 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07721 }
07722 if (!res && vms->oldmessages)
07723 res = ast_play_and_wait(chan, "vm-and");
07724 }
07725 if (!res && vms->oldmessages) {
07726 num = div(vms->oldmessages, 10);
07727 if (vms->oldmessages == 1) {
07728 res = ast_play_and_wait(chan, "digits/1-a");
07729 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
07730 res = res ? res : ast_play_and_wait(chan, "vm-message");
07731 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07732 if (num.rem == 2) {
07733 if (!num.quot) {
07734 res = ast_play_and_wait(chan, "digits/2-ie");
07735 } else {
07736 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
07737 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07738 }
07739 } else {
07740 res = say_and_wait(chan, vms->oldmessages, chan->language);
07741 }
07742 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
07743 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07744 } else {
07745 res = say_and_wait(chan, vms->oldmessages, chan->language);
07746 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
07747 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07748 }
07749 }
07750
07751 return res;
07752 }
07753
07754
07755 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
07756 {
07757
07758 int res;
07759
07760 res = ast_play_and_wait(chan, "vm-youhave");
07761 if (res)
07762 return res;
07763
07764 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07765 res = ast_play_and_wait(chan, "vm-no");
07766 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07767 return res;
07768 }
07769
07770 if (vms->newmessages) {
07771 if ((vms->newmessages == 1)) {
07772 res = ast_play_and_wait(chan, "digits/ett");
07773 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
07774 res = res ? res : ast_play_and_wait(chan, "vm-message");
07775 } else {
07776 res = say_and_wait(chan, vms->newmessages, chan->language);
07777 res = res ? res : ast_play_and_wait(chan, "vm-nya");
07778 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07779 }
07780 if (!res && vms->oldmessages)
07781 res = ast_play_and_wait(chan, "vm-and");
07782 }
07783 if (!res && vms->oldmessages) {
07784 if (vms->oldmessages == 1) {
07785 res = ast_play_and_wait(chan, "digits/ett");
07786 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
07787 res = res ? res : ast_play_and_wait(chan, "vm-message");
07788 } else {
07789 res = say_and_wait(chan, vms->oldmessages, chan->language);
07790 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
07791 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07792 }
07793 }
07794
07795 return res;
07796 }
07797
07798
07799 static int vm_intro_no(struct ast_channel *chan,struct vm_state *vms)
07800 {
07801
07802 int res;
07803
07804 res = ast_play_and_wait(chan, "vm-youhave");
07805 if (res)
07806 return res;
07807
07808 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07809 res = ast_play_and_wait(chan, "vm-no");
07810 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07811 return res;
07812 }
07813
07814 if (vms->newmessages) {
07815 if ((vms->newmessages == 1)) {
07816 res = ast_play_and_wait(chan, "digits/1");
07817 res = res ? res : ast_play_and_wait(chan, "vm-ny");
07818 res = res ? res : ast_play_and_wait(chan, "vm-message");
07819 } else {
07820 res = say_and_wait(chan, vms->newmessages, chan->language);
07821 res = res ? res : ast_play_and_wait(chan, "vm-nye");
07822 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07823 }
07824 if (!res && vms->oldmessages)
07825 res = ast_play_and_wait(chan, "vm-and");
07826 }
07827 if (!res && vms->oldmessages) {
07828 if (vms->oldmessages == 1) {
07829 res = ast_play_and_wait(chan, "digits/1");
07830 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
07831 res = res ? res : ast_play_and_wait(chan, "vm-message");
07832 } else {
07833 res = say_and_wait(chan, vms->oldmessages, chan->language);
07834 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
07835 res = res ? res : ast_play_and_wait(chan, "vm-messages");
07836 }
07837 }
07838
07839 return res;
07840 }
07841
07842
07843 static int vm_intro_de(struct ast_channel *chan,struct vm_state *vms)
07844 {
07845
07846 int res;
07847 res = ast_play_and_wait(chan, "vm-youhave");
07848 if (!res) {
07849 if (vms->newmessages) {
07850 if ((vms->newmessages == 1))
07851 res = ast_play_and_wait(chan, "digits/1F");
07852 else
07853 res = say_and_wait(chan, vms->newmessages, chan->language);
07854 if (!res)
07855 res = ast_play_and_wait(chan, "vm-INBOX");
07856 if (vms->oldmessages && !res)
07857 res = ast_play_and_wait(chan, "vm-and");
07858 else if (!res) {
07859 if ((vms->newmessages == 1))
07860 res = ast_play_and_wait(chan, "vm-message");
07861 else
07862 res = ast_play_and_wait(chan, "vm-messages");
07863 }
07864
07865 }
07866 if (!res && vms->oldmessages) {
07867 if (vms->oldmessages == 1)
07868 res = ast_play_and_wait(chan, "digits/1F");
07869 else
07870 res = say_and_wait(chan, vms->oldmessages, chan->language);
07871 if (!res)
07872 res = ast_play_and_wait(chan, "vm-Old");
07873 if (!res) {
07874 if (vms->oldmessages == 1)
07875 res = ast_play_and_wait(chan, "vm-message");
07876 else
07877 res = ast_play_and_wait(chan, "vm-messages");
07878 }
07879 }
07880 if (!res) {
07881 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07882 res = ast_play_and_wait(chan, "vm-no");
07883 if (!res)
07884 res = ast_play_and_wait(chan, "vm-messages");
07885 }
07886 }
07887 }
07888 return res;
07889 }
07890
07891
07892 static int vm_intro_es(struct ast_channel *chan,struct vm_state *vms)
07893 {
07894
07895 int res;
07896 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07897 res = ast_play_and_wait(chan, "vm-youhaveno");
07898 if (!res)
07899 res = ast_play_and_wait(chan, "vm-messages");
07900 } else {
07901 res = ast_play_and_wait(chan, "vm-youhave");
07902 }
07903 if (!res) {
07904 if (vms->newmessages) {
07905 if (!res) {
07906 if ((vms->newmessages == 1)) {
07907 res = ast_play_and_wait(chan, "digits/1M");
07908 if (!res)
07909 res = ast_play_and_wait(chan, "vm-message");
07910 if (!res)
07911 res = ast_play_and_wait(chan, "vm-INBOXs");
07912 } else {
07913 res = say_and_wait(chan, vms->newmessages, chan->language);
07914 if (!res)
07915 res = ast_play_and_wait(chan, "vm-messages");
07916 if (!res)
07917 res = ast_play_and_wait(chan, "vm-INBOX");
07918 }
07919 }
07920 if (vms->oldmessages && !res)
07921 res = ast_play_and_wait(chan, "vm-and");
07922 }
07923 if (vms->oldmessages) {
07924 if (!res) {
07925 if (vms->oldmessages == 1) {
07926 res = ast_play_and_wait(chan, "digits/1M");
07927 if (!res)
07928 res = ast_play_and_wait(chan, "vm-message");
07929 if (!res)
07930 res = ast_play_and_wait(chan, "vm-Olds");
07931 } else {
07932 res = say_and_wait(chan, vms->oldmessages, chan->language);
07933 if (!res)
07934 res = ast_play_and_wait(chan, "vm-messages");
07935 if (!res)
07936 res = ast_play_and_wait(chan, "vm-Old");
07937 }
07938 }
07939 }
07940 }
07941 return res;
07942 }
07943
07944
07945 static int vm_intro_pt_BR(struct ast_channel *chan,struct vm_state *vms) {
07946
07947 int res;
07948 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
07949 res = ast_play_and_wait(chan, "vm-nomessages");
07950 return res;
07951 } else {
07952 res = ast_play_and_wait(chan, "vm-youhave");
07953 }
07954 if (vms->newmessages) {
07955 if (!res)
07956 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
07957 if ((vms->newmessages == 1)) {
07958 if (!res)
07959 res = ast_play_and_wait(chan, "vm-message");
07960 if (!res)
07961 res = ast_play_and_wait(chan, "vm-INBOXs");
07962 } else {
07963 if (!res)
07964 res = ast_play_and_wait(chan, "vm-messages");
07965 if (!res)
07966 res = ast_play_and_wait(chan, "vm-INBOX");
07967 }
07968 if (vms->oldmessages && !res)
07969 res = ast_play_and_wait(chan, "vm-and");
07970 }
07971 if (vms->oldmessages) {
07972 if (!res)
07973 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
07974 if (vms->oldmessages == 1) {
07975 if (!res)
07976 res = ast_play_and_wait(chan, "vm-message");
07977 if (!res)
07978 res = ast_play_and_wait(chan, "vm-Olds");
07979 } else {
07980 if (!res)
07981 res = ast_play_and_wait(chan, "vm-messages");
07982 if (!res)
07983 res = ast_play_and_wait(chan, "vm-Old");
07984 }
07985 }
07986 return res;
07987 }
07988
07989
07990 static int vm_intro_fr(struct ast_channel *chan,struct vm_state *vms)
07991 {
07992
07993 int res;
07994 res = ast_play_and_wait(chan, "vm-youhave");
07995 if (!res) {
07996 if (vms->newmessages) {
07997 res = say_and_wait(chan, vms->newmessages, chan->language);
07998 if (!res)
07999 res = ast_play_and_wait(chan, "vm-INBOX");
08000 if (vms->oldmessages && !res)
08001 res = ast_play_and_wait(chan, "vm-and");
08002 else if (!res) {
08003 if ((vms->newmessages == 1))
08004 res = ast_play_and_wait(chan, "vm-message");
08005 else
08006 res = ast_play_and_wait(chan, "vm-messages");
08007 }
08008
08009 }
08010 if (!res && vms->oldmessages) {
08011 res = say_and_wait(chan, vms->oldmessages, chan->language);
08012 if (!res)
08013 res = ast_play_and_wait(chan, "vm-Old");
08014 if (!res) {
08015 if (vms->oldmessages == 1)
08016 res = ast_play_and_wait(chan, "vm-message");
08017 else
08018 res = ast_play_and_wait(chan, "vm-messages");
08019 }
08020 }
08021 if (!res) {
08022 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08023 res = ast_play_and_wait(chan, "vm-no");
08024 if (!res)
08025 res = ast_play_and_wait(chan, "vm-messages");
08026 }
08027 }
08028 }
08029 return res;
08030 }
08031
08032
08033 static int vm_intro_nl(struct ast_channel *chan,struct vm_state *vms)
08034 {
08035
08036 int res;
08037 res = ast_play_and_wait(chan, "vm-youhave");
08038 if (!res) {
08039 if (vms->newmessages) {
08040 res = say_and_wait(chan, vms->newmessages, chan->language);
08041 if (!res) {
08042 if (vms->newmessages == 1)
08043 res = ast_play_and_wait(chan, "vm-INBOXs");
08044 else
08045 res = ast_play_and_wait(chan, "vm-INBOX");
08046 }
08047 if (vms->oldmessages && !res)
08048 res = ast_play_and_wait(chan, "vm-and");
08049 else if (!res) {
08050 if ((vms->newmessages == 1))
08051 res = ast_play_and_wait(chan, "vm-message");
08052 else
08053 res = ast_play_and_wait(chan, "vm-messages");
08054 }
08055
08056 }
08057 if (!res && vms->oldmessages) {
08058 res = say_and_wait(chan, vms->oldmessages, chan->language);
08059 if (!res) {
08060 if (vms->oldmessages == 1)
08061 res = ast_play_and_wait(chan, "vm-Olds");
08062 else
08063 res = ast_play_and_wait(chan, "vm-Old");
08064 }
08065 if (!res) {
08066 if (vms->oldmessages == 1)
08067 res = ast_play_and_wait(chan, "vm-message");
08068 else
08069 res = ast_play_and_wait(chan, "vm-messages");
08070 }
08071 }
08072 if (!res) {
08073 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08074 res = ast_play_and_wait(chan, "vm-no");
08075 if (!res)
08076 res = ast_play_and_wait(chan, "vm-messages");
08077 }
08078 }
08079 }
08080 return res;
08081 }
08082
08083
08084 static int vm_intro_pt(struct ast_channel *chan,struct vm_state *vms)
08085 {
08086
08087 int res;
08088 res = ast_play_and_wait(chan, "vm-youhave");
08089 if (!res) {
08090 if (vms->newmessages) {
08091 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08092 if (!res) {
08093 if ((vms->newmessages == 1)) {
08094 res = ast_play_and_wait(chan, "vm-message");
08095 if (!res)
08096 res = ast_play_and_wait(chan, "vm-INBOXs");
08097 } else {
08098 res = ast_play_and_wait(chan, "vm-messages");
08099 if (!res)
08100 res = ast_play_and_wait(chan, "vm-INBOX");
08101 }
08102 }
08103 if (vms->oldmessages && !res)
08104 res = ast_play_and_wait(chan, "vm-and");
08105 }
08106 if (!res && vms->oldmessages) {
08107 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08108 if (!res) {
08109 if (vms->oldmessages == 1) {
08110 res = ast_play_and_wait(chan, "vm-message");
08111 if (!res)
08112 res = ast_play_and_wait(chan, "vm-Olds");
08113 } else {
08114 res = ast_play_and_wait(chan, "vm-messages");
08115 if (!res)
08116 res = ast_play_and_wait(chan, "vm-Old");
08117 }
08118 }
08119 }
08120 if (!res) {
08121 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08122 res = ast_play_and_wait(chan, "vm-no");
08123 if (!res)
08124 res = ast_play_and_wait(chan, "vm-messages");
08125 }
08126 }
08127 }
08128 return res;
08129 }
08130
08131
08132
08133
08134
08135
08136
08137
08138
08139
08140
08141
08142
08143
08144
08145
08146
08147 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08148 {
08149 int res;
08150 res = ast_play_and_wait(chan, "vm-youhave");
08151 if (!res) {
08152 if (vms->newmessages) {
08153 if (vms->newmessages == 1) {
08154 res = ast_play_and_wait(chan, "digits/jednu");
08155 } else {
08156 res = say_and_wait(chan, vms->newmessages, chan->language);
08157 }
08158 if (!res) {
08159 if ((vms->newmessages == 1))
08160 res = ast_play_and_wait(chan, "vm-novou");
08161 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08162 res = ast_play_and_wait(chan, "vm-nove");
08163 if (vms->newmessages > 4)
08164 res = ast_play_and_wait(chan, "vm-novych");
08165 }
08166 if (vms->oldmessages && !res)
08167 res = ast_play_and_wait(chan, "vm-and");
08168 else if (!res) {
08169 if ((vms->newmessages == 1))
08170 res = ast_play_and_wait(chan, "vm-zpravu");
08171 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08172 res = ast_play_and_wait(chan, "vm-zpravy");
08173 if (vms->newmessages > 4)
08174 res = ast_play_and_wait(chan, "vm-zprav");
08175 }
08176 }
08177 if (!res && vms->oldmessages) {
08178 res = say_and_wait(chan, vms->oldmessages, chan->language);
08179 if (!res) {
08180 if ((vms->oldmessages == 1))
08181 res = ast_play_and_wait(chan, "vm-starou");
08182 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08183 res = ast_play_and_wait(chan, "vm-stare");
08184 if (vms->oldmessages > 4)
08185 res = ast_play_and_wait(chan, "vm-starych");
08186 }
08187 if (!res) {
08188 if ((vms->oldmessages == 1))
08189 res = ast_play_and_wait(chan, "vm-zpravu");
08190 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08191 res = ast_play_and_wait(chan, "vm-zpravy");
08192 if (vms->oldmessages > 4)
08193 res = ast_play_and_wait(chan, "vm-zprav");
08194 }
08195 }
08196 if (!res) {
08197 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08198 res = ast_play_and_wait(chan, "vm-no");
08199 if (!res)
08200 res = ast_play_and_wait(chan, "vm-zpravy");
08201 }
08202 }
08203 }
08204 return res;
08205 }
08206
08207
08208 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
08209 {
08210 int res;
08211
08212 res = ast_play_and_wait(chan, "vm-you");
08213
08214 if (!res && vms->newmessages) {
08215 res = ast_play_and_wait(chan, "vm-have");
08216 if (!res)
08217 res = say_and_wait(chan, vms->newmessages, chan->language);
08218 if (!res)
08219 res = ast_play_and_wait(chan, "vm-tong");
08220 if (!res)
08221 res = ast_play_and_wait(chan, "vm-INBOX");
08222 if (vms->oldmessages && !res)
08223 res = ast_play_and_wait(chan, "vm-and");
08224 else if (!res)
08225 res = ast_play_and_wait(chan, "vm-messages");
08226 }
08227 if (!res && vms->oldmessages) {
08228 res = ast_play_and_wait(chan, "vm-have");
08229 if (!res)
08230 res = say_and_wait(chan, vms->oldmessages, chan->language);
08231 if (!res)
08232 res = ast_play_and_wait(chan, "vm-tong");
08233 if (!res)
08234 res = ast_play_and_wait(chan, "vm-Old");
08235 if (!res)
08236 res = ast_play_and_wait(chan, "vm-messages");
08237 }
08238 if (!res && !vms->oldmessages && !vms->newmessages) {
08239 res = ast_play_and_wait(chan, "vm-haveno");
08240 if (!res)
08241 res = ast_play_and_wait(chan, "vm-messages");
08242 }
08243 return res;
08244 }
08245
08246 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
08247 {
08248 char prefile[256];
08249
08250
08251 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
08252 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
08253 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
08254 if (ast_fileexists(prefile, NULL, NULL) > 0) {
08255 ast_play_and_wait(chan, "vm-tempgreetactive");
08256 }
08257 DISPOSE(prefile, -1);
08258 }
08259
08260
08261 if (0) {
08262 return 0;
08263 } else if (!strncasecmp(chan->language, "cs", 2)) {
08264 return vm_intro_cs(chan, vms);
08265 } else if (!strncasecmp(chan->language, "cz", 2)) {
08266 static int deprecation_warning = 0;
08267 if (deprecation_warning++ % 10 == 0) {
08268 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
08269 }
08270 return vm_intro_cs(chan, vms);
08271 } else if (!strncasecmp(chan->language, "de", 2)) {
08272 return vm_intro_de(chan, vms);
08273 } else if (!strncasecmp(chan->language, "es", 2)) {
08274 return vm_intro_es(chan, vms);
08275 } else if (!strncasecmp(chan->language, "fr", 2)) {
08276 return vm_intro_fr(chan, vms);
08277 } else if (!strncasecmp(chan->language, "gr", 2)) {
08278 return vm_intro_gr(chan, vms);
08279 } else if (!strncasecmp(chan->language, "he", 2)) {
08280 return vm_intro_he(chan, vms);
08281 } else if (!strncasecmp(chan->language, "it", 2)) {
08282 return vm_intro_it(chan, vms);
08283 } else if (!strncasecmp(chan->language, "nl", 2)) {
08284 return vm_intro_nl(chan, vms);
08285 } else if (!strncasecmp(chan->language, "no", 2)) {
08286 return vm_intro_no(chan, vms);
08287 } else if (!strncasecmp(chan->language, "pl", 2)) {
08288 return vm_intro_pl(chan, vms);
08289 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
08290 return vm_intro_pt_BR(chan, vms);
08291 } else if (!strncasecmp(chan->language, "pt", 2)) {
08292 return vm_intro_pt(chan, vms);
08293 } else if (!strncasecmp(chan->language, "ru", 2)) {
08294 return vm_intro_multilang(chan, vms, "n");
08295 } else if (!strncasecmp(chan->language, "se", 2)) {
08296 return vm_intro_se(chan, vms);
08297 } else if (!strncasecmp(chan->language, "ua", 2)) {
08298 return vm_intro_multilang(chan, vms, "n");
08299 } else if (!strncasecmp(chan->language, "zh", 2)) {
08300 return vm_intro_zh(chan, vms);
08301 } else {
08302 return vm_intro_en(chan, vms);
08303 }
08304 }
08305
08306 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08307 {
08308 int res = 0;
08309
08310 while (!res) {
08311 if (vms->starting) {
08312 if (vms->lastmsg > -1) {
08313 if (skipadvanced)
08314 res = ast_play_and_wait(chan, "vm-onefor-full");
08315 else
08316 res = ast_play_and_wait(chan, "vm-onefor");
08317 if (!res)
08318 res = vm_play_folder_name(chan, vms->vmbox);
08319 }
08320 if (!res) {
08321 if (skipadvanced)
08322 res = ast_play_and_wait(chan, "vm-opts-full");
08323 else
08324 res = ast_play_and_wait(chan, "vm-opts");
08325 }
08326 } else {
08327
08328 if (skipadvanced) {
08329 res = ast_play_and_wait(chan, "vm-onefor-full");
08330 if (!res)
08331 res = vm_play_folder_name(chan, vms->vmbox);
08332 res = ast_play_and_wait(chan, "vm-opts-full");
08333 }
08334
08335
08336
08337
08338
08339
08340 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
08341 res = ast_play_and_wait(chan, "vm-prev");
08342 }
08343 if (!res && !skipadvanced)
08344 res = ast_play_and_wait(chan, "vm-advopts");
08345 if (!res)
08346 res = ast_play_and_wait(chan, "vm-repeat");
08347
08348
08349
08350
08351
08352
08353 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
08354 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
08355 res = ast_play_and_wait(chan, "vm-next");
08356 }
08357 if (!res) {
08358 if (!vms->deleted[vms->curmsg])
08359 res = ast_play_and_wait(chan, "vm-delete");
08360 else
08361 res = ast_play_and_wait(chan, "vm-undelete");
08362 if (!res)
08363 res = ast_play_and_wait(chan, "vm-toforward");
08364 if (!res)
08365 res = ast_play_and_wait(chan, "vm-savemessage");
08366 }
08367 }
08368 if (!res) {
08369 res = ast_play_and_wait(chan, "vm-helpexit");
08370 }
08371 if (!res)
08372 res = ast_waitfordigit(chan, 6000);
08373 if (!res) {
08374 vms->repeats++;
08375 if (vms->repeats > 2) {
08376 res = 't';
08377 }
08378 }
08379 }
08380 return res;
08381 }
08382
08383 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08384 {
08385 int res = 0;
08386
08387 while (!res) {
08388 if (vms->lastmsg > -1) {
08389 res = ast_play_and_wait(chan, "vm-listen");
08390 if (!res)
08391 res = vm_play_folder_name(chan, vms->vmbox);
08392 if (!res)
08393 res = ast_play_and_wait(chan, "press");
08394 if (!res)
08395 res = ast_play_and_wait(chan, "digits/1");
08396 }
08397 if (!res)
08398 res = ast_play_and_wait(chan, "vm-opts");
08399 if (!res) {
08400 vms->starting = 0;
08401 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
08402 }
08403 }
08404 return res;
08405 }
08406
08407 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
08408 {
08409 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
08410 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
08411 } else {
08412 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
08413 }
08414 }
08415
08416
08417 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
08418 {
08419 int cmd = 0;
08420 int duration = 0;
08421 int tries = 0;
08422 char newpassword[80] = "";
08423 char newpassword2[80] = "";
08424 char prefile[PATH_MAX] = "";
08425 unsigned char buf[256];
08426 int bytes=0;
08427
08428 if (ast_adsi_available(chan)) {
08429 bytes += adsi_logo(buf + bytes);
08430 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
08431 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
08432 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
08433 bytes += ast_adsi_voice_mode(buf + bytes, 0);
08434 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
08435 }
08436
08437
08438
08439 for (;;) {
08440 newpassword[1] = '\0';
08441 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
08442 if (cmd == '#')
08443 newpassword[0] = '\0';
08444 if (cmd < 0 || cmd == 't' || cmd == '#')
08445 return cmd;
08446 cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#");
08447 if (cmd < 0 || cmd == 't' || cmd == '#')
08448 return cmd;
08449 cmd = check_password(vmu, newpassword);
08450 if (cmd != 0) {
08451 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
08452 cmd = ast_play_and_wait(chan, vm_invalid_password);
08453 } else {
08454 newpassword2[1] = '\0';
08455 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
08456 if (cmd == '#')
08457 newpassword2[0] = '\0';
08458 if (cmd < 0 || cmd == 't' || cmd == '#')
08459 return cmd;
08460 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
08461 if (cmd < 0 || cmd == 't' || cmd == '#')
08462 return cmd;
08463 if (!strcmp(newpassword, newpassword2))
08464 break;
08465 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
08466 cmd = ast_play_and_wait(chan, vm_mismatch);
08467 }
08468 if (++tries == 3)
08469 return -1;
08470 if (cmd != 0) {
08471 cmd = ast_play_and_wait(chan, vm_pls_try_again);
08472 }
08473 }
08474 if (pwdchange & PWDCHANGE_INTERNAL)
08475 vm_change_password(vmu, newpassword);
08476 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
08477 vm_change_password_shell(vmu, newpassword);
08478
08479 ast_debug(1,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
08480 cmd = ast_play_and_wait(chan, vm_passchanged);
08481
08482
08483 if (ast_test_flag(vmu, VM_FORCENAME)) {
08484 snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
08485 if (ast_fileexists(prefile, NULL, NULL) < 1) {
08486 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08487 if (cmd < 0 || cmd == 't' || cmd == '#')
08488 return cmd;
08489 }
08490 }
08491
08492
08493 if (ast_test_flag(vmu, VM_FORCEGREET)) {
08494 snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
08495 if (ast_fileexists(prefile, NULL, NULL) < 1) {
08496 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08497 if (cmd < 0 || cmd == 't' || cmd == '#')
08498 return cmd;
08499 }
08500
08501 snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
08502 if (ast_fileexists(prefile, NULL, NULL) < 1) {
08503 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08504 if (cmd < 0 || cmd == 't' || cmd == '#')
08505 return cmd;
08506 }
08507 }
08508
08509 return cmd;
08510 }
08511
08512 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
08513 {
08514 int cmd = 0;
08515 int retries = 0;
08516 int duration = 0;
08517 char newpassword[80] = "";
08518 char newpassword2[80] = "";
08519 char prefile[PATH_MAX] = "";
08520 unsigned char buf[256];
08521 int bytes=0;
08522
08523 if (ast_adsi_available(chan)) {
08524 bytes += adsi_logo(buf + bytes);
08525 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
08526 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
08527 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
08528 bytes += ast_adsi_voice_mode(buf + bytes, 0);
08529 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
08530 }
08531 while ((cmd >= 0) && (cmd != 't')) {
08532 if (cmd)
08533 retries = 0;
08534 switch (cmd) {
08535 case '1':
08536 snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
08537 cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08538 break;
08539 case '2':
08540 snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
08541 cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08542 break;
08543 case '3':
08544 snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
08545 cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08546 break;
08547 case '4':
08548 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
08549 break;
08550 case '5':
08551 if (vmu->password[0] == '-') {
08552 cmd = ast_play_and_wait(chan, "vm-no");
08553 break;
08554 }
08555 newpassword[1] = '\0';
08556 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
08557 if (cmd == '#')
08558 newpassword[0] = '\0';
08559 else {
08560 if (cmd < 0)
08561 break;
08562 if ((cmd = ast_readstring(chan,newpassword + strlen(newpassword),sizeof(newpassword)-1,2000,10000,"#")) < 0) {
08563 break;
08564 }
08565 }
08566 cmd = check_password(vmu, newpassword);
08567 if (cmd != 0) {
08568 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
08569 cmd = ast_play_and_wait(chan, vm_invalid_password);
08570 if (!cmd) {
08571 cmd = ast_play_and_wait(chan, vm_pls_try_again);
08572 }
08573 break;
08574 }
08575 newpassword2[1] = '\0';
08576 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
08577 if (cmd == '#')
08578 newpassword2[0] = '\0';
08579 else {
08580 if (cmd < 0)
08581 break;
08582
08583 if ((cmd = ast_readstring(chan,newpassword2 + strlen(newpassword2),sizeof(newpassword2)-1,2000,10000,"#")) < 0) {
08584 break;
08585 }
08586 }
08587 if (strcmp(newpassword, newpassword2)) {
08588 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
08589 cmd = ast_play_and_wait(chan, vm_mismatch);
08590 if (!cmd) {
08591 cmd = ast_play_and_wait(chan, vm_pls_try_again);
08592 }
08593 break;
08594 }
08595 if (pwdchange & PWDCHANGE_INTERNAL)
08596 vm_change_password(vmu, newpassword);
08597 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
08598 vm_change_password_shell(vmu, newpassword);
08599
08600 ast_debug(1,"User %s set password to %s of length %d\n",vms->username,newpassword,(int)strlen(newpassword));
08601 cmd = ast_play_and_wait(chan, vm_passchanged);
08602 break;
08603 case '*':
08604 cmd = 't';
08605 break;
08606 default:
08607 cmd = 0;
08608 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
08609 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
08610 if (ast_fileexists(prefile, NULL, NULL)) {
08611 cmd = ast_play_and_wait(chan, "vm-tmpexists");
08612 }
08613 DISPOSE(prefile, -1);
08614 if (!cmd) {
08615 cmd = ast_play_and_wait(chan, "vm-options");
08616 }
08617 if (!cmd) {
08618 cmd = ast_waitfordigit(chan,6000);
08619 }
08620 if (!cmd) {
08621 retries++;
08622 }
08623 if (retries > 3) {
08624 cmd = 't';
08625 }
08626 }
08627 }
08628 if (cmd == 't')
08629 cmd = 0;
08630 return cmd;
08631 }
08632
08633
08634
08635
08636
08637
08638
08639
08640
08641
08642
08643
08644
08645
08646
08647
08648
08649 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
08650 {
08651 int cmd = 0;
08652 int retries = 0;
08653 int duration = 0;
08654 char prefile[PATH_MAX] = "";
08655 unsigned char buf[256];
08656 int bytes = 0;
08657
08658 if (ast_adsi_available(chan)) {
08659 bytes += adsi_logo(buf + bytes);
08660 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
08661 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
08662 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
08663 bytes += ast_adsi_voice_mode(buf + bytes, 0);
08664 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
08665 }
08666
08667 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
08668 while ((cmd >= 0) && (cmd != 't')) {
08669 if (cmd)
08670 retries = 0;
08671 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
08672 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
08673 play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08674 cmd = 't';
08675 } else {
08676 switch (cmd) {
08677 case '1':
08678 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain, vms, NULL);
08679 break;
08680 case '2':
08681 DELETE(prefile, -1, prefile, vmu);
08682 ast_play_and_wait(chan, "vm-tempremoved");
08683 cmd = 't';
08684 break;
08685 case '*':
08686 cmd = 't';
08687 break;
08688 default:
08689 cmd = ast_play_and_wait(chan,
08690 ast_fileexists(prefile, NULL, NULL) > 0 ?
08691 "vm-tempgreeting2" : "vm-tempgreeting");
08692 if (!cmd)
08693 cmd = ast_waitfordigit(chan,6000);
08694 if (!cmd)
08695 retries++;
08696 if (retries > 3)
08697 cmd = 't';
08698 }
08699 }
08700 DISPOSE(prefile, -1);
08701 }
08702 if (cmd == 't')
08703 cmd = 0;
08704 return cmd;
08705 }
08706
08707
08708
08709
08710
08711
08712
08713
08714
08715 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08716 {
08717 int cmd=0;
08718
08719 if (vms->lastmsg > -1) {
08720 cmd = play_message(chan, vmu, vms);
08721 } else {
08722 cmd = ast_play_and_wait(chan, "vm-youhaveno");
08723 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
08724 if (!cmd) {
08725 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
08726 cmd = ast_play_and_wait(chan, vms->fn);
08727 }
08728 if (!cmd)
08729 cmd = ast_play_and_wait(chan, "vm-messages");
08730 } else {
08731 if (!cmd)
08732 cmd = ast_play_and_wait(chan, "vm-messages");
08733 if (!cmd) {
08734 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
08735 cmd = ast_play_and_wait(chan, vms->fn);
08736 }
08737 }
08738 }
08739 return cmd;
08740 }
08741
08742
08743 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08744 {
08745 int cmd = 0;
08746
08747 if (vms->lastmsg > -1) {
08748 cmd = play_message(chan, vmu, vms);
08749 } else {
08750 if (!strcasecmp(vms->fn, "INBOX")) {
08751 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
08752 } else {
08753 cmd = ast_play_and_wait(chan, "vm-nomessages");
08754 }
08755 }
08756 return cmd;
08757 }
08758
08759
08760
08761
08762
08763
08764
08765
08766
08767 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08768 {
08769 int cmd=0;
08770
08771 if (vms->lastmsg > -1) {
08772 cmd = play_message(chan, vmu, vms);
08773 } else {
08774 cmd = ast_play_and_wait(chan, "vm-youhave");
08775 if (!cmd)
08776 cmd = ast_play_and_wait(chan, "vm-no");
08777 if (!cmd) {
08778 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
08779 cmd = ast_play_and_wait(chan, vms->fn);
08780 }
08781 if (!cmd)
08782 cmd = ast_play_and_wait(chan, "vm-messages");
08783 }
08784 return cmd;
08785 }
08786
08787
08788
08789
08790
08791
08792
08793
08794
08795 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08796 {
08797 int cmd=0;
08798
08799 if (vms->lastmsg > -1) {
08800 cmd = play_message(chan, vmu, vms);
08801 } else {
08802 cmd = ast_play_and_wait(chan, "vm-no");
08803 if (!cmd)
08804 cmd = ast_play_and_wait(chan, "vm-message");
08805 if (!cmd) {
08806 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
08807 cmd = ast_play_and_wait(chan, vms->fn);
08808 }
08809 }
08810 return cmd;
08811 }
08812
08813
08814
08815
08816
08817
08818
08819
08820
08821 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08822 {
08823 int cmd=0;
08824
08825 if (vms->lastmsg > -1) {
08826 cmd = play_message(chan, vmu, vms);
08827 } else {
08828 cmd = ast_play_and_wait(chan, "vm-youhaveno");
08829 if (!cmd)
08830 cmd = ast_play_and_wait(chan, "vm-messages");
08831 if (!cmd) {
08832 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
08833 cmd = ast_play_and_wait(chan, vms->fn);
08834 }
08835 }
08836 return cmd;
08837 }
08838
08839
08840
08841
08842
08843
08844
08845
08846
08847 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08848 {
08849 int cmd=0;
08850
08851 if (vms->lastmsg > -1) {
08852 cmd = play_message(chan, vmu, vms);
08853 } else {
08854 cmd = ast_play_and_wait(chan, "vm-no");
08855 if (!cmd) {
08856 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
08857 cmd = ast_play_and_wait(chan, vms->fn);
08858 }
08859 if (!cmd)
08860 cmd = ast_play_and_wait(chan, "vm-messages");
08861 }
08862 return cmd;
08863 }
08864
08865
08866
08867
08868
08869
08870
08871
08872
08873 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08874 {
08875 int cmd=0;
08876
08877 if (vms->lastmsg > -1) {
08878 cmd = play_message(chan, vmu, vms);
08879 } else {
08880 cmd = ast_play_and_wait(chan, "vm-you");
08881 if (!cmd)
08882 cmd = ast_play_and_wait(chan, "vm-haveno");
08883 if (!cmd)
08884 cmd = ast_play_and_wait(chan, "vm-messages");
08885 if (!cmd) {
08886 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
08887 cmd = ast_play_and_wait(chan, vms->fn);
08888 }
08889 }
08890 return cmd;
08891 }
08892
08893
08894
08895
08896
08897
08898
08899
08900
08901
08902
08903
08904 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
08905 {
08906 if (!strncasecmp(chan->language, "es", 2)) {
08907 return vm_browse_messages_es(chan, vms, vmu);
08908 } else if (!strncasecmp(chan->language, "gr", 2)) {
08909 return vm_browse_messages_gr(chan, vms, vmu);
08910 } else if (!strncasecmp(chan->language, "he", 2)) {
08911 return vm_browse_messages_he(chan, vms, vmu);
08912 } else if (!strncasecmp(chan->language, "it", 2)) {
08913 return vm_browse_messages_it(chan, vms, vmu);
08914 } else if (!strncasecmp(chan->language, "pt", 2)) {
08915 return vm_browse_messages_pt(chan, vms, vmu);
08916 } else if (!strncasecmp(chan->language, "zh", 2)) {
08917 return vm_browse_messages_zh(chan, vms, vmu);
08918 } else {
08919 return vm_browse_messages_en(chan, vms, vmu);
08920 }
08921 }
08922
08923 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
08924 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
08925 int skipuser, int max_logins, int silent)
08926 {
08927 int useadsi=0, valid=0, logretries=0;
08928 char password[AST_MAX_EXTENSION]="", *passptr;
08929 struct ast_vm_user vmus, *vmu = NULL;
08930
08931
08932 adsi_begin(chan, &useadsi);
08933 if (!skipuser && useadsi)
08934 adsi_login(chan);
08935 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
08936 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
08937 return -1;
08938 }
08939
08940
08941
08942 while (!valid && (logretries < max_logins)) {
08943
08944 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
08945 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
08946 return -1;
08947 }
08948 if (ast_strlen_zero(mailbox)) {
08949 if (chan->cid.cid_num) {
08950 ast_copy_string(mailbox, chan->cid.cid_num, mailbox_size);
08951 } else {
08952 ast_verb(3,"Username not entered\n");
08953 return -1;
08954 }
08955 }
08956 if (useadsi)
08957 adsi_password(chan);
08958
08959 if (!ast_strlen_zero(prefix)) {
08960 char fullusername[80] = "";
08961 ast_copy_string(fullusername, prefix, sizeof(fullusername));
08962 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
08963 ast_copy_string(mailbox, fullusername, mailbox_size);
08964 }
08965
08966 ast_debug(1, "Before find user for mailbox %s\n",mailbox);
08967 vmu = find_user(&vmus, context, mailbox);
08968 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
08969
08970 password[0] = '\0';
08971 } else {
08972 if (ast_streamfile(chan, vm_password, chan->language)) {
08973 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
08974 return -1;
08975 }
08976 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
08977 ast_log(AST_LOG_WARNING, "Unable to read password\n");
08978 return -1;
08979 }
08980 }
08981
08982 if (vmu) {
08983 passptr = vmu->password;
08984 if (passptr[0] == '-') passptr++;
08985 }
08986 if (vmu && !strcmp(passptr, password))
08987 valid++;
08988 else {
08989 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
08990 if (!ast_strlen_zero(prefix))
08991 mailbox[0] = '\0';
08992 }
08993 logretries++;
08994 if (!valid) {
08995 if (skipuser || logretries >= max_logins) {
08996 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
08997 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
08998 return -1;
08999 }
09000 } else {
09001 if (useadsi)
09002 adsi_login(chan);
09003 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09004 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09005 return -1;
09006 }
09007 }
09008 if (ast_waitstream(chan, ""))
09009 return -1;
09010 }
09011 }
09012 if (!valid && (logretries >= max_logins)) {
09013 ast_stopstream(chan);
09014 ast_play_and_wait(chan, "vm-goodbye");
09015 return -1;
09016 }
09017 if (vmu && !skipuser) {
09018 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09019 }
09020 return 0;
09021 }
09022
09023 static int vm_execmain(struct ast_channel *chan, void *data)
09024 {
09025
09026
09027
09028 int res=-1;
09029 int cmd=0;
09030 int valid = 0;
09031 char prefixstr[80] ="";
09032 char ext_context[256]="";
09033 int box;
09034 int useadsi = 0;
09035 int skipuser = 0;
09036 struct vm_state vms;
09037 struct ast_vm_user *vmu = NULL, vmus;
09038 char *context=NULL;
09039 int silentexit = 0;
09040 struct ast_flags flags = { 0 };
09041 signed char record_gain = 0;
09042 int play_auto = 0;
09043 int play_folder = 0;
09044 int in_urgent = 0;
09045 #ifdef IMAP_STORAGE
09046 int deleted = 0;
09047 #endif
09048
09049
09050 memset(&vms, 0, sizeof(vms));
09051
09052 vms.lastmsg = -1;
09053
09054 memset(&vmus, 0, sizeof(vmus));
09055
09056 if (chan->_state != AST_STATE_UP) {
09057 ast_debug(1, "Before ast_answer\n");
09058 ast_answer(chan);
09059 }
09060
09061 if (!ast_strlen_zero(data)) {
09062 char *opts[OPT_ARG_ARRAY_SIZE];
09063 char *parse;
09064 AST_DECLARE_APP_ARGS(args,
09065 AST_APP_ARG(argv0);
09066 AST_APP_ARG(argv1);
09067 );
09068
09069 parse = ast_strdupa(data);
09070
09071 AST_STANDARD_APP_ARGS(args, parse);
09072
09073 if (args.argc == 2) {
09074 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09075 return -1;
09076 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09077 int gain;
09078 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09079 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09080 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09081 return -1;
09082 } else {
09083 record_gain = (signed char) gain;
09084 }
09085 } else {
09086 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09087 }
09088 }
09089 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09090 play_auto = 1;
09091 if (opts[OPT_ARG_PLAYFOLDER]) {
09092 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09093 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for folder autoplay option\n", opts[OPT_ARG_PLAYFOLDER]);
09094 }
09095 } else {
09096 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
09097 }
09098 if ( play_folder > 9 || play_folder < 0) {
09099 ast_log(AST_LOG_WARNING, "Invalid value '%d' provided for folder autoplay option\n", play_folder);
09100 play_folder = 0;
09101 }
09102 }
09103 } else {
09104
09105 while (*(args.argv0)) {
09106 if (*(args.argv0) == 's')
09107 ast_set_flag(&flags, OPT_SILENT);
09108 else if (*(args.argv0) == 'p')
09109 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
09110 else
09111 break;
09112 (args.argv0)++;
09113 }
09114
09115 }
09116
09117 valid = ast_test_flag(&flags, OPT_SILENT);
09118
09119 if ((context = strchr(args.argv0, '@')))
09120 *context++ = '\0';
09121
09122 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
09123 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
09124 else
09125 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
09126
09127 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
09128 skipuser++;
09129 else
09130 valid = 0;
09131 }
09132
09133 if (!valid)
09134 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
09135
09136 ast_debug(1, "After vm_authenticate\n");
09137 if (!res) {
09138 valid = 1;
09139 if (!skipuser)
09140 vmu = &vmus;
09141 } else {
09142 res = 0;
09143 }
09144
09145
09146 adsi_begin(chan, &useadsi);
09147
09148 if (!valid) {
09149 goto out;
09150 }
09151
09152 #ifdef IMAP_STORAGE
09153 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
09154 pthread_setspecific(ts_vmstate.key, &vms);
09155
09156 vms.interactive = 1;
09157 vms.updated = 1;
09158 if (vmu)
09159 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
09160 vmstate_insert(&vms);
09161 init_vm_state(&vms);
09162 #endif
09163 if (!(vms.deleted = ast_calloc(vmu->maxmsg, sizeof(int)))) {
09164 ast_log(AST_LOG_ERROR, "Could not allocate memory for deleted message storage!\n");
09165 cmd = ast_play_and_wait(chan, "an-error-has-occured");
09166 return -1;
09167 }
09168 if (!(vms.heard = ast_calloc(vmu->maxmsg, sizeof(int)))) {
09169 ast_log(AST_LOG_ERROR, "Could not allocate memory for heard message storage!\n");
09170 cmd = ast_play_and_wait(chan, "an-error-has-occured");
09171 return -1;
09172 }
09173
09174
09175 if (!ast_strlen_zero(vmu->language))
09176 ast_string_field_set(chan, language, vmu->language);
09177
09178
09179 ast_debug(1, "Before open_mailbox\n");
09180 res = open_mailbox(&vms, vmu, OLD_FOLDER);
09181 if (res == ERROR_LOCK_PATH)
09182 goto out;
09183 vms.oldmessages = vms.lastmsg + 1;
09184 ast_debug(1, "Number of old messages: %d\n",vms.oldmessages);
09185
09186 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09187 if (res == ERROR_LOCK_PATH)
09188 goto out;
09189 vms.newmessages = vms.lastmsg + 1;
09190 ast_debug(1, "Number of new messages: %d\n",vms.newmessages);
09191
09192 in_urgent = 1;
09193 res = open_mailbox(&vms, vmu, 11);
09194 if (res == ERROR_LOCK_PATH)
09195 goto out;
09196 vms.urgentmessages = vms.lastmsg + 1;
09197 ast_debug(1, "Number of urgent messages: %d\n",vms.urgentmessages);
09198
09199
09200 if (play_auto) {
09201 if (vms.urgentmessages) {
09202 in_urgent = 1;
09203 res = open_mailbox(&vms, vmu, 11);
09204 } else {
09205 in_urgent = 0;
09206 res = open_mailbox(&vms, vmu, play_folder);
09207 }
09208 if (res == ERROR_LOCK_PATH)
09209 goto out;
09210
09211
09212 if (vms.lastmsg == -1) {
09213 in_urgent = 0;
09214 cmd = vm_browse_messages(chan, &vms, vmu);
09215 res = 0;
09216 goto out;
09217 }
09218 } else {
09219 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
09220
09221 res = open_mailbox(&vms, vmu, OLD_FOLDER);
09222 in_urgent = 0;
09223 play_folder = 1;
09224 if (res == ERROR_LOCK_PATH)
09225 goto out;
09226 } else if (!vms.urgentmessages && vms.newmessages) {
09227
09228 in_urgent = 0;
09229 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09230 if (res == ERROR_LOCK_PATH)
09231 goto out;
09232 }
09233 }
09234
09235 if (useadsi)
09236 adsi_status(chan, &vms);
09237 res = 0;
09238
09239
09240 if (!strcasecmp(vmu->mailbox, vmu->password) &&
09241 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
09242 if (ast_play_and_wait(chan, "vm-newuser") == -1)
09243 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
09244 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
09245 if ((cmd == 't') || (cmd == '#')) {
09246
09247 res = 0;
09248 goto out;
09249 } else if (cmd < 0) {
09250
09251 res = -1;
09252 goto out;
09253 }
09254 }
09255 #ifdef IMAP_STORAGE
09256 ast_debug(3, "Checking quotas: comparing %u to %u\n",vms.quota_usage,vms.quota_limit);
09257 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
09258 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
09259 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
09260 }
09261 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n",(vms.newmessages + vms.oldmessages),vmu->maxmsg);
09262 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
09263 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
09264 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
09265 }
09266 #endif
09267 if (play_auto) {
09268 cmd = '1';
09269 } else {
09270 cmd = vm_intro(chan, vmu, &vms);
09271 }
09272
09273 vms.repeats = 0;
09274 vms.starting = 1;
09275 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
09276
09277 switch (cmd) {
09278 case '1':
09279 vms.curmsg = 0;
09280
09281 case '5':
09282 cmd = vm_browse_messages(chan, &vms, vmu);
09283 break;
09284 case '2':
09285 if (useadsi)
09286 adsi_folders(chan, 0, "Change to folder...");
09287 cmd = get_folder2(chan, "vm-changeto", 0);
09288 if (cmd == '#') {
09289 cmd = 0;
09290 } else if (cmd > 0) {
09291 cmd = cmd - '0';
09292 res = close_mailbox(&vms, vmu);
09293 if (res == ERROR_LOCK_PATH)
09294 goto out;
09295
09296 if (cmd != 11) in_urgent = 0;
09297 res = open_mailbox(&vms, vmu, cmd);
09298 if (res == ERROR_LOCK_PATH)
09299 goto out;
09300 play_folder = cmd;
09301 cmd = 0;
09302 }
09303 if (useadsi)
09304 adsi_status2(chan, &vms);
09305
09306 if (!cmd)
09307 cmd = vm_play_folder_name(chan, vms.vmbox);
09308
09309 vms.starting = 1;
09310 break;
09311 case '3':
09312 cmd = 0;
09313 vms.repeats = 0;
09314 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
09315 switch (cmd) {
09316 case '1':
09317 if (vms.lastmsg > -1 && !vms.starting) {
09318 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
09319 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
09320 res = cmd;
09321 goto out;
09322 }
09323 } else
09324 cmd = ast_play_and_wait(chan, "vm-sorry");
09325 cmd = 't';
09326 break;
09327 case '2':
09328 if (!vms.starting)
09329 ast_verb(3, "Callback Requested\n");
09330 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
09331 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
09332 if (cmd == 9) {
09333 silentexit = 1;
09334 goto out;
09335 } else if (cmd == ERROR_LOCK_PATH) {
09336 res = cmd;
09337 goto out;
09338 }
09339 } else
09340 cmd = ast_play_and_wait(chan, "vm-sorry");
09341 cmd = 't';
09342 break;
09343 case '3':
09344 if (vms.lastmsg > -1 && !vms.starting) {
09345 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
09346 if (cmd == ERROR_LOCK_PATH) {
09347 res = cmd;
09348 goto out;
09349 }
09350 } else
09351 cmd = ast_play_and_wait(chan, "vm-sorry");
09352 cmd = 't';
09353 break;
09354 case '4':
09355 if (!ast_strlen_zero(vmu->dialout)) {
09356 cmd = dialout(chan, vmu, NULL, vmu->dialout);
09357 if (cmd == 9) {
09358 silentexit = 1;
09359 goto out;
09360 }
09361 } else
09362 cmd = ast_play_and_wait(chan, "vm-sorry");
09363 cmd = 't';
09364 break;
09365
09366 case '5':
09367 if (ast_test_flag(vmu, VM_SVMAIL)) {
09368 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
09369 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
09370 res = cmd;
09371 goto out;
09372 }
09373 } else
09374 cmd = ast_play_and_wait(chan,"vm-sorry");
09375 cmd='t';
09376 break;
09377
09378 case '*':
09379 cmd = 't';
09380 break;
09381
09382 default:
09383 cmd = 0;
09384 if (!vms.starting) {
09385 cmd = ast_play_and_wait(chan, "vm-toreply");
09386 }
09387 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
09388 cmd = ast_play_and_wait(chan, "vm-tocallback");
09389 }
09390 if (!cmd && !vms.starting) {
09391 cmd = ast_play_and_wait(chan, "vm-tohearenv");
09392 }
09393 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
09394 cmd = ast_play_and_wait(chan, "vm-tomakecall");
09395 }
09396 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd)
09397 cmd=ast_play_and_wait(chan, "vm-leavemsg");
09398 if (!cmd)
09399 cmd = ast_play_and_wait(chan, "vm-starmain");
09400 if (!cmd)
09401 cmd = ast_waitfordigit(chan,6000);
09402 if (!cmd)
09403 vms.repeats++;
09404 if (vms.repeats > 3)
09405 cmd = 't';
09406 }
09407 }
09408 if (cmd == 't') {
09409 cmd = 0;
09410 vms.repeats = 0;
09411 }
09412 break;
09413 case '4':
09414 if (vms.curmsg > 0) {
09415 vms.curmsg--;
09416 cmd = play_message(chan, vmu, &vms);
09417 } else {
09418
09419
09420
09421
09422 if (in_urgent == 0 && vms.urgentmessages > 0) {
09423
09424 in_urgent = 1;
09425 res = close_mailbox(&vms, vmu);
09426 if (res == ERROR_LOCK_PATH)
09427 goto out;
09428 res = open_mailbox(&vms, vmu, 11);
09429 if (res == ERROR_LOCK_PATH)
09430 goto out;
09431 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n",vms.lastmsg + 1);
09432 vms.curmsg = vms.lastmsg;
09433 if (vms.lastmsg < 0)
09434 cmd = ast_play_and_wait(chan, "vm-nomore");
09435 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
09436 vms.curmsg = vms.lastmsg;
09437 cmd = play_message(chan, vmu, &vms);
09438 } else {
09439 cmd = ast_play_and_wait(chan, "vm-nomore");
09440 }
09441 }
09442 break;
09443 case '6':
09444 if (vms.curmsg < vms.lastmsg) {
09445 vms.curmsg++;
09446 cmd = play_message(chan, vmu, &vms);
09447 } else {
09448 if (in_urgent && vms.newmessages > 0) {
09449
09450
09451
09452
09453 in_urgent = 0;
09454 res = close_mailbox(&vms, vmu);
09455 if (res == ERROR_LOCK_PATH)
09456 goto out;
09457 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09458 if (res == ERROR_LOCK_PATH)
09459 goto out;
09460 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n",vms.lastmsg + 1);
09461 vms.curmsg = -1;
09462 if (vms.lastmsg < 0) {
09463 cmd = ast_play_and_wait(chan, "vm-nomore");
09464 }
09465 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
09466 vms.curmsg = 0;
09467 cmd = play_message(chan, vmu, &vms);
09468 } else {
09469 cmd = ast_play_and_wait(chan, "vm-nomore");
09470 }
09471 }
09472 break;
09473 case '7':
09474 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
09475 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
09476 if (useadsi)
09477 adsi_delete(chan, &vms);
09478 if (vms.deleted[vms.curmsg]) {
09479 if (play_folder == 0) {
09480 if (in_urgent) {
09481 vms.urgentmessages--;
09482 } else {
09483 vms.newmessages--;
09484 }
09485 }
09486 else if (play_folder == 1)
09487 vms.oldmessages--;
09488 cmd = ast_play_and_wait(chan, "vm-deleted");
09489 } else {
09490 if (play_folder == 0) {
09491 if (in_urgent) {
09492 vms.urgentmessages++;
09493 } else {
09494 vms.newmessages++;
09495 }
09496 }
09497 else if (play_folder == 1)
09498 vms.oldmessages++;
09499 cmd = ast_play_and_wait(chan, "vm-undeleted");
09500 }
09501 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
09502 if (vms.curmsg < vms.lastmsg) {
09503 vms.curmsg++;
09504 cmd = play_message(chan, vmu, &vms);
09505 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
09506 vms.curmsg = 0;
09507 cmd = play_message(chan, vmu, &vms);
09508 } else {
09509
09510
09511
09512
09513 if (in_urgent == 1) {
09514
09515 in_urgent = 0;
09516 res = close_mailbox(&vms, vmu);
09517 if (res == ERROR_LOCK_PATH)
09518 goto out;
09519 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09520 if (res == ERROR_LOCK_PATH)
09521 goto out;
09522 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n",vms.lastmsg + 1);
09523 vms.curmsg = -1;
09524 if (vms.lastmsg < 0)
09525 cmd = ast_play_and_wait(chan, "vm-nomore");
09526 } else {
09527 cmd = ast_play_and_wait(chan, "vm-nomore");
09528 }
09529 }
09530 }
09531 } else
09532 cmd = 0;
09533 #ifdef IMAP_STORAGE
09534 deleted = 1;
09535 #endif
09536 break;
09537
09538 case '8':
09539 if (vms.lastmsg > -1) {
09540 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
09541 if (cmd == ERROR_LOCK_PATH) {
09542 res = cmd;
09543 goto out;
09544 }
09545 } else {
09546
09547
09548
09549
09550 if (in_urgent == 1 && vms.newmessages > 0) {
09551
09552 in_urgent = 0;
09553 res = close_mailbox(&vms, vmu);
09554 if (res == ERROR_LOCK_PATH)
09555 goto out;
09556 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09557 if (res == ERROR_LOCK_PATH)
09558 goto out;
09559 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n",vms.lastmsg + 1);
09560 vms.curmsg = -1;
09561 if (vms.lastmsg < 0)
09562 cmd = ast_play_and_wait(chan, "vm-nomore");
09563 } else {
09564 cmd = ast_play_and_wait(chan, "vm-nomore");
09565 }
09566 }
09567 break;
09568 case '9':
09569 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
09570
09571 cmd = 0;
09572 break;
09573 }
09574 if (useadsi)
09575 adsi_folders(chan, 1, "Save to folder...");
09576 cmd = get_folder2(chan, "vm-savefolder", 1);
09577 box = 0;
09578 if (cmd == '#') {
09579 cmd = 0;
09580 break;
09581 } else if (cmd > 0) {
09582 box = cmd = cmd - '0';
09583 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
09584 if (cmd == ERROR_LOCK_PATH) {
09585 res = cmd;
09586 goto out;
09587 #ifndef IMAP_STORAGE
09588 } else if (!cmd) {
09589 vms.deleted[vms.curmsg] = 1;
09590 #endif
09591 } else {
09592 vms.deleted[vms.curmsg] = 0;
09593 vms.heard[vms.curmsg] = 0;
09594 }
09595 }
09596 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
09597 if (useadsi)
09598 adsi_message(chan, &vms);
09599 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(box));
09600 if (!cmd) {
09601 cmd = ast_play_and_wait(chan, "vm-message");
09602 if (!cmd)
09603 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
09604 if (!cmd)
09605 cmd = ast_play_and_wait(chan, "vm-savedto");
09606 if (!cmd)
09607 cmd = vm_play_folder_name(chan, vms.fn);
09608 } else {
09609 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
09610 }
09611 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
09612 if (vms.curmsg < vms.lastmsg) {
09613 vms.curmsg++;
09614 cmd = play_message(chan, vmu, &vms);
09615 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
09616 vms.curmsg = 0;
09617 cmd = play_message(chan, vmu, &vms);
09618 } else {
09619
09620
09621
09622
09623 if (in_urgent == 1 && vms.newmessages > 0) {
09624
09625 in_urgent = 0;
09626 res = close_mailbox(&vms, vmu);
09627 if (res == ERROR_LOCK_PATH)
09628 goto out;
09629 res = open_mailbox(&vms, vmu, NEW_FOLDER);
09630 if (res == ERROR_LOCK_PATH)
09631 goto out;
09632 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n",vms.lastmsg + 1);
09633 vms.curmsg = -1;
09634 if (vms.lastmsg < 0)
09635 cmd = ast_play_and_wait(chan, "vm-nomore");
09636 } else {
09637 cmd = ast_play_and_wait(chan, "vm-nomore");
09638 }
09639 }
09640 }
09641 break;
09642 case '*':
09643 if (!vms.starting) {
09644 cmd = ast_play_and_wait(chan, "vm-onefor");
09645 if (!strncasecmp(chan->language, "he", 2)) {
09646 cmd = ast_play_and_wait(chan, "vm-for");
09647 }
09648 if (!cmd)
09649 cmd = vm_play_folder_name(chan, vms.vmbox);
09650 if (!cmd)
09651 cmd = ast_play_and_wait(chan, "vm-opts");
09652 if (!cmd)
09653 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
09654 } else
09655 cmd = 0;
09656 break;
09657 case '0':
09658 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
09659 if (useadsi)
09660 adsi_status(chan, &vms);
09661 break;
09662 default:
09663 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
09664 break;
09665 }
09666 }
09667 if ((cmd == 't') || (cmd == '#')) {
09668
09669 res = 0;
09670 } else {
09671
09672 res = -1;
09673 }
09674
09675 out:
09676 if (res > -1) {
09677 ast_stopstream(chan);
09678 adsi_goodbye(chan);
09679 if (valid && res != OPERATOR_EXIT) {
09680 if (silentexit)
09681 res = ast_play_and_wait(chan, "vm-dialout");
09682 else
09683 res = ast_play_and_wait(chan, "vm-goodbye");
09684 }
09685 if ((valid && res > 0) || res == OPERATOR_EXIT) {
09686 res = 0;
09687 }
09688 if (useadsi)
09689 ast_adsi_unload_session(chan);
09690 }
09691 if (vmu)
09692 close_mailbox(&vms, vmu);
09693 if (valid) {
09694 int new = 0, old = 0, urgent = 0;
09695 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
09696 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
09697
09698 run_externnotify(vmu->context, vmu->mailbox, NULL);
09699 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
09700 queue_mwi_event(ext_context, urgent, new, old);
09701 }
09702 #ifdef IMAP_STORAGE
09703
09704 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n",deleted,expungeonhangup);
09705 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
09706 ast_mutex_lock(&vms.lock);
09707 #ifdef HAVE_IMAP_TK2006
09708 if (LEVELUIDPLUS (vms.mailstream)) {
09709 mail_expunge_full(vms.mailstream,NIL,EX_UID);
09710 } else
09711 #endif
09712 mail_expunge(vms.mailstream);
09713 ast_mutex_unlock(&vms.lock);
09714 }
09715
09716
09717 if (vmu) {
09718 vmstate_delete(&vms);
09719 }
09720 #endif
09721 if (vmu)
09722 free_user(vmu);
09723 if (vms.deleted)
09724 ast_free(vms.deleted);
09725 if (vms.heard)
09726 ast_free(vms.heard);
09727
09728 #ifdef IMAP_STORAGE
09729 pthread_setspecific(ts_vmstate.key, NULL);
09730 #endif
09731 return res;
09732 }
09733
09734 static int vm_exec(struct ast_channel *chan, void *data)
09735 {
09736 int res = 0;
09737 char *tmp;
09738 struct leave_vm_options leave_options;
09739 struct ast_flags flags = { 0 };
09740 char *opts[OPT_ARG_ARRAY_SIZE];
09741 AST_DECLARE_APP_ARGS(args,
09742 AST_APP_ARG(argv0);
09743 AST_APP_ARG(argv1);
09744 );
09745
09746 memset(&leave_options, 0, sizeof(leave_options));
09747
09748 if (chan->_state != AST_STATE_UP)
09749 ast_answer(chan);
09750
09751 if (!ast_strlen_zero(data)) {
09752 tmp = ast_strdupa(data);
09753 AST_STANDARD_APP_ARGS(args, tmp);
09754 if (args.argc == 2) {
09755 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09756 return -1;
09757 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
09758 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09759 int gain;
09760
09761 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09762 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09763 return -1;
09764 } else {
09765 leave_options.record_gain = (signed char) gain;
09766 }
09767 }
09768 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
09769 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
09770 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
09771 }
09772 }
09773 } else {
09774 char temp[256];
09775 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
09776 if (res < 0)
09777 return res;
09778 if (ast_strlen_zero(temp))
09779 return 0;
09780 args.argv0 = ast_strdupa(temp);
09781 }
09782
09783 res = leave_voicemail(chan, args.argv0, &leave_options);
09784 if (res == OPERATOR_EXIT) {
09785 res = 0;
09786 }
09787
09788 if (res == ERROR_LOCK_PATH) {
09789 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
09790 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
09791 res = 0;
09792 }
09793
09794 return res;
09795 }
09796
09797 static struct ast_vm_user *find_or_create(const char *context, const char *box)
09798 {
09799 struct ast_vm_user *vmu;
09800
09801 AST_LIST_TRAVERSE(&users, vmu, list) {
09802 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
09803 if (strcasecmp(vmu->context, context)) {
09804 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
09805 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
09806 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
09807 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
09808 }
09809 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
09810 return NULL;
09811 }
09812 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
09813 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
09814 return NULL;
09815 }
09816 }
09817
09818 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
09819 return NULL;
09820
09821 ast_copy_string(vmu->context, context, sizeof(vmu->context));
09822 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
09823
09824 AST_LIST_INSERT_TAIL(&users, vmu, list);
09825
09826 return vmu;
09827 }
09828
09829 static int append_mailbox(const char *context, const char *box, const char *data)
09830 {
09831
09832 char *tmp;
09833 char *stringp;
09834 char *s;
09835 struct ast_vm_user *vmu;
09836 char *mailbox_full;
09837 int new = 0, old = 0, urgent = 0;
09838
09839 tmp = ast_strdupa(data);
09840
09841 if (!(vmu = find_or_create(context, box)))
09842 return -1;
09843
09844 populate_defaults(vmu);
09845
09846 stringp = tmp;
09847 if ((s = strsep(&stringp, ",")))
09848 ast_copy_string(vmu->password, s, sizeof(vmu->password));
09849 if (stringp && (s = strsep(&stringp, ",")))
09850 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
09851 if (stringp && (s = strsep(&stringp, ",")))
09852 ast_copy_string(vmu->email, s, sizeof(vmu->email));
09853 if (stringp && (s = strsep(&stringp, ",")))
09854 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
09855 if (stringp && (s = strsep(&stringp, ",")))
09856 apply_options(vmu, s);
09857
09858 mailbox_full = alloca(strlen(box) + strlen(context) + 1);
09859 strcpy(mailbox_full, box);
09860 strcat(mailbox_full, "@");
09861 strcat(mailbox_full, context);
09862
09863 inboxcount2(mailbox_full, &urgent, &new, &old);
09864 queue_mwi_event(mailbox_full, urgent, new, old);
09865
09866 return 0;
09867 }
09868
09869 static int vm_box_exists(struct ast_channel *chan, void *data)
09870 {
09871 struct ast_vm_user svm;
09872 char *context, *box;
09873 AST_DECLARE_APP_ARGS(args,
09874 AST_APP_ARG(mbox);
09875 AST_APP_ARG(options);
09876 );
09877 static int dep_warning = 0;
09878
09879 if (ast_strlen_zero(data)) {
09880 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
09881 return -1;
09882 }
09883
09884 if (!dep_warning) {
09885 dep_warning = 1;
09886 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *)data);
09887 }
09888
09889 box = ast_strdupa(data);
09890
09891 AST_STANDARD_APP_ARGS(args, box);
09892
09893 if (args.options) {
09894 }
09895
09896 if ((context = strchr(args.mbox, '@'))) {
09897 *context = '\0';
09898 context++;
09899 }
09900
09901 if (find_user(&svm, context, args.mbox)) {
09902 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
09903 } else
09904 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
09905
09906 return 0;
09907 }
09908
09909 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
09910 {
09911 struct ast_vm_user svm;
09912 AST_DECLARE_APP_ARGS(arg,
09913 AST_APP_ARG(mbox);
09914 AST_APP_ARG(context);
09915 );
09916
09917 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
09918
09919 if (ast_strlen_zero(arg.mbox)) {
09920 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
09921 return -1;
09922 }
09923
09924 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
09925 return 0;
09926 }
09927
09928 static struct ast_custom_function mailbox_exists_acf = {
09929 .name = "MAILBOX_EXISTS",
09930 .synopsis = "Tell if a mailbox is configured",
09931 .desc =
09932 "Returns a boolean of whether the corresponding mailbox exists. If context\n"
09933 "is not specified, defaults to the \"default\" context.\n",
09934 .syntax = "MAILBOX_EXISTS(<vmbox>[@<context>])",
09935 .read = acf_mailbox_exists,
09936 };
09937
09938 static int vmauthenticate(struct ast_channel *chan, void *data)
09939 {
09940 char *s = data, *user=NULL, *context=NULL, mailbox[AST_MAX_EXTENSION] = "";
09941 struct ast_vm_user vmus;
09942 char *options = NULL;
09943 int silent = 0, skipuser = 0;
09944 int res = -1;
09945
09946 if (s) {
09947 s = ast_strdupa(s);
09948 user = strsep(&s, ",");
09949 options = strsep(&s, ",");
09950 if (user) {
09951 s = user;
09952 user = strsep(&s, "@");
09953 context = strsep(&s, "");
09954 if (!ast_strlen_zero(user))
09955 skipuser++;
09956 ast_copy_string(mailbox, user, sizeof(mailbox));
09957 }
09958 }
09959
09960 if (options) {
09961 silent = (strchr(options, 's')) != NULL;
09962 }
09963
09964 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
09965 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
09966 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
09967 ast_play_and_wait(chan, "auth-thankyou");
09968 res = 0;
09969 }
09970
09971 return res;
09972 }
09973
09974 static char *show_users_realtime(int fd, const char *context)
09975 {
09976 struct ast_config *cfg;
09977 const char *cat = NULL;
09978
09979 if (!(cfg = ast_load_realtime_multientry("voicemail",
09980 "context", context, SENTINEL))) {
09981 return CLI_FAILURE;
09982 }
09983
09984 ast_cli(fd,
09985 "\n"
09986 "=============================================================\n"
09987 "=== Configured Voicemail Users ==============================\n"
09988 "=============================================================\n"
09989 "===\n");
09990
09991 while ((cat = ast_category_browse(cfg, cat))) {
09992 struct ast_variable *var = NULL;
09993 ast_cli(fd,
09994 "=== Mailbox ...\n"
09995 "===\n");
09996 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
09997 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
09998 ast_cli(fd,
09999 "===\n"
10000 "=== ---------------------------------------------------------\n"
10001 "===\n");
10002 }
10003
10004 ast_cli(fd,
10005 "=============================================================\n"
10006 "\n");
10007
10008 ast_config_destroy(cfg);
10009
10010 return CLI_SUCCESS;
10011 }
10012
10013 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
10014 {
10015 int which = 0;
10016 int wordlen;
10017 struct ast_vm_user *vmu;
10018 const char *context = "";
10019
10020
10021 if (pos > 4)
10022 return NULL;
10023 if (pos == 3)
10024 return (state == 0) ? ast_strdup("for") : NULL;
10025 wordlen = strlen(word);
10026 AST_LIST_TRAVERSE(&users, vmu, list) {
10027 if (!strncasecmp(word, vmu->context, wordlen)) {
10028 if (context && strcmp(context, vmu->context) && ++which > state)
10029 return ast_strdup(vmu->context);
10030
10031 context = vmu->context;
10032 }
10033 }
10034 return NULL;
10035 }
10036
10037
10038 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10039 {
10040 struct ast_vm_user *vmu;
10041 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
10042 const char *context = NULL;
10043 int users_counter = 0;
10044
10045 switch (cmd) {
10046 case CLI_INIT:
10047 e->command = "voicemail show users";
10048 e->usage =
10049 "Usage: voicemail show users [for <context>]\n"
10050 " Lists all mailboxes currently set up\n";
10051 return NULL;
10052 case CLI_GENERATE:
10053 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
10054 }
10055
10056 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
10057 return CLI_SHOWUSAGE;
10058 if (a->argc == 5) {
10059 if (strcmp(a->argv[3],"for"))
10060 return CLI_SHOWUSAGE;
10061 context = a->argv[4];
10062 }
10063
10064 if (ast_check_realtime("voicemail")) {
10065 if (!context) {
10066 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
10067 return CLI_SHOWUSAGE;
10068 }
10069 return show_users_realtime(a->fd, context);
10070 }
10071
10072 AST_LIST_LOCK(&users);
10073 if (AST_LIST_EMPTY(&users)) {
10074 ast_cli(a->fd, "There are no voicemail users currently defined\n");
10075 AST_LIST_UNLOCK(&users);
10076 return CLI_FAILURE;
10077 }
10078 if (a->argc == 3)
10079 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
10080 else {
10081 int count = 0;
10082 AST_LIST_TRAVERSE(&users, vmu, list) {
10083 if (!strcmp(context, vmu->context))
10084 count++;
10085 }
10086 if (count) {
10087 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
10088 } else {
10089 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
10090 AST_LIST_UNLOCK(&users);
10091 return CLI_FAILURE;
10092 }
10093 }
10094 AST_LIST_TRAVERSE(&users, vmu, list) {
10095 int newmsgs = 0, oldmsgs = 0;
10096 char count[12], tmp[256] = "";
10097
10098 if ((a->argc == 3) || ((a->argc == 5) && !strcmp(context, vmu->context))) {
10099 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
10100 inboxcount(tmp, &newmsgs, &oldmsgs);
10101 snprintf(count, sizeof(count), "%d", newmsgs);
10102 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
10103 users_counter++;
10104 }
10105 }
10106 AST_LIST_UNLOCK(&users);
10107 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
10108 return CLI_SUCCESS;
10109 }
10110
10111
10112 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10113 {
10114 struct vm_zone *zone;
10115 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
10116 char *res = CLI_SUCCESS;
10117
10118 switch (cmd) {
10119 case CLI_INIT:
10120 e->command = "voicemail show zones";
10121 e->usage =
10122 "Usage: voicemail show zones\n"
10123 " Lists zone message formats\n";
10124 return NULL;
10125 case CLI_GENERATE:
10126 return NULL;
10127 }
10128
10129 if (a->argc != 3)
10130 return CLI_SHOWUSAGE;
10131
10132 AST_LIST_LOCK(&zones);
10133 if (!AST_LIST_EMPTY(&zones)) {
10134 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
10135 AST_LIST_TRAVERSE(&zones, zone, list) {
10136 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
10137 }
10138 } else {
10139 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
10140 res = CLI_FAILURE;
10141 }
10142 AST_LIST_UNLOCK(&zones);
10143
10144 return res;
10145 }
10146
10147
10148 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10149 {
10150 switch (cmd) {
10151 case CLI_INIT:
10152 e->command = "voicemail reload";
10153 e->usage =
10154 "Usage: voicemail reload\n"
10155 " Reload voicemail configuration\n";
10156 return NULL;
10157 case CLI_GENERATE:
10158 return NULL;
10159 }
10160
10161 if (a->argc != 2)
10162 return CLI_SHOWUSAGE;
10163
10164 ast_cli(a->fd, "Reloading voicemail configuration...\n");
10165 load_config(1);
10166
10167 return CLI_SUCCESS;
10168 }
10169
10170 static struct ast_cli_entry cli_voicemail[] = {
10171 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
10172 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
10173 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
10174 };
10175
10176 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
10177 {
10178 int new = 0, old = 0, urgent = 0;
10179
10180 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
10181
10182 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
10183 mwi_sub->old_urgent = urgent;
10184 mwi_sub->old_new = new;
10185 mwi_sub->old_old = old;
10186 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
10187 }
10188 }
10189
10190 static void poll_subscribed_mailboxes(void)
10191 {
10192 struct mwi_sub *mwi_sub;
10193
10194 AST_RWLIST_RDLOCK(&mwi_subs);
10195 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
10196 if (!ast_strlen_zero(mwi_sub->mailbox)) {
10197 poll_subscribed_mailbox(mwi_sub);
10198 }
10199 }
10200 AST_RWLIST_UNLOCK(&mwi_subs);
10201 }
10202
10203 static void *mb_poll_thread(void *data)
10204 {
10205 while (poll_thread_run) {
10206 struct timespec ts = { 0, };
10207 struct timeval wait;
10208
10209 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
10210 ts.tv_sec = wait.tv_sec;
10211 ts.tv_nsec = wait.tv_usec * 1000;
10212
10213 ast_mutex_lock(&poll_lock);
10214 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
10215 ast_mutex_unlock(&poll_lock);
10216
10217 if (!poll_thread_run)
10218 break;
10219
10220 poll_subscribed_mailboxes();
10221 }
10222
10223 return NULL;
10224 }
10225
10226 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
10227 {
10228 ast_free(mwi_sub);
10229 }
10230
10231 static int handle_unsubscribe(void *datap)
10232 {
10233 struct mwi_sub *mwi_sub;
10234 uint32_t *uniqueid = datap;
10235
10236 AST_RWLIST_WRLOCK(&mwi_subs);
10237 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
10238 if (mwi_sub->uniqueid == *uniqueid) {
10239 AST_LIST_REMOVE_CURRENT(entry);
10240 break;
10241 }
10242 }
10243 AST_RWLIST_TRAVERSE_SAFE_END
10244 AST_RWLIST_UNLOCK(&mwi_subs);
10245
10246 if (mwi_sub)
10247 mwi_sub_destroy(mwi_sub);
10248
10249 ast_free(uniqueid);
10250 return 0;
10251 }
10252
10253 static int handle_subscribe(void *datap)
10254 {
10255 unsigned int len;
10256 struct mwi_sub *mwi_sub;
10257 struct mwi_sub_task *p = datap;
10258
10259 len = sizeof(*mwi_sub);
10260 if (!ast_strlen_zero(p->mailbox))
10261 len += strlen(p->mailbox);
10262
10263 if (!ast_strlen_zero(p->context))
10264 len += strlen(p->context) + 1;
10265
10266 if (!(mwi_sub = ast_calloc(1, len)))
10267 return -1;
10268
10269 mwi_sub->uniqueid = p->uniqueid;
10270 if (!ast_strlen_zero(p->mailbox))
10271 strcpy(mwi_sub->mailbox, p->mailbox);
10272
10273 if (!ast_strlen_zero(p->context)) {
10274 strcat(mwi_sub->mailbox, "@");
10275 strcat(mwi_sub->mailbox, p->context);
10276 }
10277
10278 AST_RWLIST_WRLOCK(&mwi_subs);
10279 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
10280 AST_RWLIST_UNLOCK(&mwi_subs);
10281 ast_free((void *) p->mailbox);
10282 ast_free((void *) p->context);
10283 ast_free(p);
10284 poll_subscribed_mailbox(mwi_sub);
10285 return 0;
10286 }
10287
10288 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
10289 {
10290 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
10291 if (ast_event_get_type(event) != AST_EVENT_UNSUB)
10292 return;
10293
10294 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
10295 return;
10296
10297 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
10298 *uniqueid = u;
10299 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
10300 ast_free(uniqueid);
10301 }
10302 }
10303
10304 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
10305 {
10306 struct mwi_sub_task *mwist;
10307
10308 if (ast_event_get_type(event) != AST_EVENT_SUB)
10309 return;
10310
10311 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
10312 return;
10313
10314 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
10315 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
10316 return;
10317 }
10318 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
10319 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
10320 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
10321
10322 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
10323 ast_free(mwist);
10324 }
10325 }
10326
10327 static void start_poll_thread(void)
10328 {
10329 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, NULL,
10330 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
10331 AST_EVENT_IE_END);
10332
10333 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, NULL,
10334 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
10335 AST_EVENT_IE_END);
10336
10337 if (mwi_sub_sub)
10338 ast_event_report_subs(mwi_sub_sub);
10339
10340 poll_thread_run = 1;
10341
10342 ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL);
10343 }
10344
10345 static void stop_poll_thread(void)
10346 {
10347 poll_thread_run = 0;
10348
10349 if (mwi_sub_sub) {
10350 ast_event_unsubscribe(mwi_sub_sub);
10351 mwi_sub_sub = NULL;
10352 }
10353
10354 if (mwi_unsub_sub) {
10355 ast_event_unsubscribe(mwi_unsub_sub);
10356 mwi_unsub_sub = NULL;
10357 }
10358
10359 ast_mutex_lock(&poll_lock);
10360 ast_cond_signal(&poll_cond);
10361 ast_mutex_unlock(&poll_lock);
10362
10363 pthread_join(poll_thread, NULL);
10364
10365 poll_thread = AST_PTHREADT_NULL;
10366 }
10367
10368
10369 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
10370 {
10371 struct ast_vm_user *vmu = NULL;
10372 const char *id = astman_get_header(m, "ActionID");
10373 char actionid[128] = "";
10374
10375 if (!ast_strlen_zero(id))
10376 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
10377
10378 AST_LIST_LOCK(&users);
10379
10380 if (AST_LIST_EMPTY(&users)) {
10381 astman_send_ack(s, m, "There are no voicemail users currently defined.");
10382 AST_LIST_UNLOCK(&users);
10383 return RESULT_SUCCESS;
10384 }
10385
10386 astman_send_ack(s, m, "Voicemail user list will follow");
10387
10388 AST_LIST_TRAVERSE(&users, vmu, list) {
10389 char dirname[256];
10390
10391 #ifdef IMAP_STORAGE
10392 int new, old;
10393 inboxcount(vmu->mailbox, &new, &old);
10394 #endif
10395
10396 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
10397 astman_append(s,
10398 "%s"
10399 "Event: VoicemailUserEntry\r\n"
10400 "VMContext: %s\r\n"
10401 "VoiceMailbox: %s\r\n"
10402 "Fullname: %s\r\n"
10403 "Email: %s\r\n"
10404 "Pager: %s\r\n"
10405 "ServerEmail: %s\r\n"
10406 "MailCommand: %s\r\n"
10407 "Language: %s\r\n"
10408 "TimeZone: %s\r\n"
10409 "Callback: %s\r\n"
10410 "Dialout: %s\r\n"
10411 "UniqueID: %s\r\n"
10412 "ExitContext: %s\r\n"
10413 "SayDurationMinimum: %d\r\n"
10414 "SayEnvelope: %s\r\n"
10415 "SayCID: %s\r\n"
10416 "AttachMessage: %s\r\n"
10417 "AttachmentFormat: %s\r\n"
10418 "DeleteMessage: %s\r\n"
10419 "VolumeGain: %.2f\r\n"
10420 "CanReview: %s\r\n"
10421 "CallOperator: %s\r\n"
10422 "MaxMessageCount: %d\r\n"
10423 "MaxMessageLength: %d\r\n"
10424 "NewMessageCount: %d\r\n"
10425 #ifdef IMAP_STORAGE
10426 "OldMessageCount: %d\r\n"
10427 "IMAPUser: %s\r\n"
10428 #endif
10429 "\r\n",
10430 actionid,
10431 vmu->context,
10432 vmu->mailbox,
10433 vmu->fullname,
10434 vmu->email,
10435 vmu->pager,
10436 vmu->serveremail,
10437 vmu->mailcmd,
10438 vmu->language,
10439 vmu->zonetag,
10440 vmu->callback,
10441 vmu->dialout,
10442 vmu->uniqueid,
10443 vmu->exit,
10444 vmu->saydurationm,
10445 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
10446 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
10447 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
10448 vmu->attachfmt,
10449 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
10450 vmu->volgain,
10451 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
10452 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
10453 vmu->maxmsg,
10454 vmu->maxsecs,
10455 #ifdef IMAP_STORAGE
10456 new, old, vmu->imapuser
10457 #else
10458 count_messages(vmu, dirname)
10459 #endif
10460 );
10461 }
10462 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
10463
10464 AST_LIST_UNLOCK(&users);
10465
10466 return RESULT_SUCCESS;
10467 }
10468
10469
10470 static void free_vm_users(void)
10471 {
10472 struct ast_vm_user *current;
10473 AST_LIST_LOCK(&users);
10474 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
10475 ast_set_flag(current, VM_ALLOCED);
10476 free_user(current);
10477 }
10478 AST_LIST_UNLOCK(&users);
10479 }
10480
10481
10482 static void free_vm_zones(void)
10483 {
10484 struct vm_zone *zcur;
10485 AST_LIST_LOCK(&zones);
10486 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
10487 free_zone(zcur);
10488 AST_LIST_UNLOCK(&zones);
10489 }
10490
10491 static char *substitute_escapes(const char *value)
10492 {
10493 char *current, *result;
10494
10495
10496 struct ast_str *str = ast_str_create(strlen(value) + 16);
10497
10498
10499 for (current = (char *) value; *current; current++) {
10500 if (*current == '\\') {
10501 current++;
10502 if (!*current) {
10503 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
10504 break;
10505 }
10506 switch (*current) {
10507 case 'r':
10508 ast_str_append(&str, 0, "\r");
10509 break;
10510 case 'n':
10511 #ifdef IMAP_STORAGE
10512 if (!str->used || str->str[str->used - 1] != '\r') {
10513 ast_str_append(&str, 0, "\r");
10514 }
10515 #endif
10516 ast_str_append(&str, 0, "\n");
10517 break;
10518 case 't':
10519 ast_str_append(&str, 0, "\t");
10520 break;
10521 default:
10522 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
10523 break;
10524 }
10525 } else {
10526 ast_str_append(&str, 0, "%c", *current);
10527 }
10528 }
10529
10530 result = ast_strdup(str->str);
10531 ast_free(str);
10532
10533 return result;
10534 }
10535
10536 static int load_config(int reload)
10537 {
10538 struct ast_vm_user *current;
10539 struct ast_config *cfg, *ucfg;
10540 char *cat;
10541 struct ast_variable *var;
10542 const char *val;
10543 char *q, *stringp, *tmp;
10544 int x;
10545 int tmpadsi[4];
10546 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
10547
10548 ast_unload_realtime("voicemail");
10549 ast_unload_realtime("voicemail_data");
10550
10551 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
10552 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED)
10553 return 0;
10554 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
10555 cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
10556 } else {
10557 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
10558 ucfg = ast_config_load("users.conf", config_flags);
10559 }
10560 #ifdef IMAP_STORAGE
10561 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
10562 #endif
10563
10564 strcpy(listen_control_forward_key,DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
10565 strcpy(listen_control_reverse_key,DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
10566 strcpy(listen_control_pause_key,DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
10567 strcpy(listen_control_restart_key,DEFAULT_LISTEN_CONTROL_RESTART_KEY);
10568 strcpy(listen_control_stop_key,DEFAULT_LISTEN_CONTROL_STOP_KEY);
10569
10570
10571 free_vm_users();
10572
10573
10574 free_vm_zones();
10575
10576 AST_LIST_LOCK(&users);
10577
10578 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
10579 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
10580
10581 if (cfg) {
10582
10583
10584 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
10585 val = "default";
10586 ast_copy_string(userscontext, val, sizeof(userscontext));
10587
10588 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
10589 val = "yes";
10590 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
10591
10592 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
10593 val = "no";
10594 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
10595
10596 volgain = 0.0;
10597 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
10598 sscanf(val, "%30lf", &volgain);
10599
10600 #ifdef ODBC_STORAGE
10601 strcpy(odbc_database, "asterisk");
10602 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
10603 ast_copy_string(odbc_database, val, sizeof(odbc_database));
10604 }
10605 strcpy(odbc_table, "voicemessages");
10606 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
10607 ast_copy_string(odbc_table, val, sizeof(odbc_table));
10608 }
10609 #endif
10610
10611 strcpy(mailcmd, SENDMAIL);
10612 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
10613 ast_copy_string(mailcmd, val, sizeof(mailcmd));
10614
10615 maxsilence = 0;
10616 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
10617 maxsilence = atoi(val);
10618 if (maxsilence > 0)
10619 maxsilence *= 1000;
10620 }
10621
10622 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
10623 maxmsg = MAXMSG;
10624 } else {
10625 maxmsg = atoi(val);
10626 if (maxmsg <= 0) {
10627 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
10628 maxmsg = MAXMSG;
10629 } else if (maxmsg > MAXMSGLIMIT) {
10630 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
10631 maxmsg = MAXMSGLIMIT;
10632 }
10633 }
10634
10635 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
10636 maxdeletedmsg = 0;
10637 } else {
10638 if (sscanf(val, "%30d", &x) == 1)
10639 maxdeletedmsg = x;
10640 else if (ast_true(val))
10641 maxdeletedmsg = MAXMSG;
10642 else
10643 maxdeletedmsg = 0;
10644
10645 if (maxdeletedmsg < 0) {
10646 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
10647 maxdeletedmsg = MAXMSG;
10648 } else if (maxdeletedmsg > MAXMSGLIMIT) {
10649 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
10650 maxdeletedmsg = MAXMSGLIMIT;
10651 }
10652 }
10653
10654
10655 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
10656 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
10657 }
10658
10659
10660 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
10661 ast_copy_string(ext_pass_cmd,val,sizeof(ext_pass_cmd));
10662 pwdchange = PWDCHANGE_EXTERNAL;
10663 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
10664 ast_copy_string(ext_pass_cmd,val,sizeof(ext_pass_cmd));
10665 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
10666 }
10667
10668
10669 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
10670 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
10671 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
10672 }
10673
10674 #ifdef IMAP_STORAGE
10675
10676 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
10677 ast_copy_string(imapserver, val, sizeof(imapserver));
10678 } else {
10679 ast_copy_string(imapserver,"localhost", sizeof(imapserver));
10680 }
10681
10682 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
10683 ast_copy_string(imapport, val, sizeof(imapport));
10684 } else {
10685 ast_copy_string(imapport,"143", sizeof(imapport));
10686 }
10687
10688 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
10689 ast_copy_string(imapflags, val, sizeof(imapflags));
10690 }
10691
10692 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
10693 ast_copy_string(authuser, val, sizeof(authuser));
10694 }
10695
10696 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
10697 ast_copy_string(authpassword, val, sizeof(authpassword));
10698 }
10699
10700 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
10701 if (ast_false(val))
10702 expungeonhangup = 0;
10703 else
10704 expungeonhangup = 1;
10705 } else {
10706 expungeonhangup = 1;
10707 }
10708
10709 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
10710 ast_copy_string(imapfolder, val, sizeof(imapfolder));
10711 } else {
10712 ast_copy_string(imapfolder,"INBOX", sizeof(imapfolder));
10713 }
10714 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
10715 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
10716 }
10717 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
10718 imapgreetings = ast_true(val);
10719 } else {
10720 imapgreetings = 0;
10721 }
10722 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
10723 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
10724 } else {
10725 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
10726 }
10727
10728
10729
10730
10731
10732 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
10733 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
10734 } else {
10735 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
10736 }
10737
10738 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
10739 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
10740 } else {
10741 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
10742 }
10743
10744 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
10745 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
10746 } else {
10747 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
10748 }
10749
10750 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
10751 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
10752 } else {
10753 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
10754 }
10755
10756
10757 imapversion++;
10758 #endif
10759
10760 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
10761 ast_copy_string(externnotify, val, sizeof(externnotify));
10762 ast_debug(1, "found externnotify: %s\n", externnotify);
10763 } else {
10764 externnotify[0] = '\0';
10765 }
10766
10767
10768 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
10769 ast_debug(1, "Enabled SMDI voicemail notification\n");
10770 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
10771 smdi_iface = ast_smdi_interface_find ? ast_smdi_interface_find(val) : NULL;
10772 } else {
10773 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
10774 smdi_iface = ast_smdi_interface_find ? ast_smdi_interface_find("/dev/ttyS0") : NULL;
10775 }
10776 if (!smdi_iface) {
10777 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
10778 }
10779 }
10780
10781
10782 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
10783 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
10784 silencethreshold = atoi(val);
10785
10786 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
10787 val = ASTERISK_USERNAME;
10788 ast_copy_string(serveremail, val, sizeof(serveremail));
10789
10790 vmmaxsecs = 0;
10791 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
10792 if (sscanf(val, "%30d", &x) == 1) {
10793 vmmaxsecs = x;
10794 } else {
10795 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
10796 }
10797 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
10798 static int maxmessage_deprecate = 0;
10799 if (maxmessage_deprecate == 0) {
10800 maxmessage_deprecate = 1;
10801 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
10802 }
10803 if (sscanf(val, "%30d", &x) == 1) {
10804 vmmaxsecs = x;
10805 } else {
10806 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
10807 }
10808 }
10809
10810 vmminsecs = 0;
10811 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
10812 if (sscanf(val, "%30d", &x) == 1) {
10813 vmminsecs = x;
10814 if (maxsilence / 1000 >= vmminsecs) {
10815 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
10816 }
10817 } else {
10818 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
10819 }
10820 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
10821 static int maxmessage_deprecate = 0;
10822 if (maxmessage_deprecate == 0) {
10823 maxmessage_deprecate = 1;
10824 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
10825 }
10826 if (sscanf(val, "%30d", &x) == 1) {
10827 vmminsecs = x;
10828 if (maxsilence / 1000 >= vmminsecs) {
10829 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
10830 }
10831 } else {
10832 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
10833 }
10834 }
10835
10836 val = ast_variable_retrieve(cfg, "general", "format");
10837 if (!val) {
10838 val = "wav";
10839 } else {
10840 tmp = ast_strdupa(val);
10841 val = ast_format_str_reduce(tmp);
10842 if (!val) {
10843 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
10844 val = "wav";
10845 }
10846 }
10847 ast_copy_string(vmfmts, val, sizeof(vmfmts));
10848
10849 skipms = 3000;
10850 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
10851 if (sscanf(val, "%30d", &x) == 1) {
10852 maxgreet = x;
10853 } else {
10854 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
10855 }
10856 }
10857
10858 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
10859 if (sscanf(val, "%30d", &x) == 1) {
10860 skipms = x;
10861 } else {
10862 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
10863 }
10864 }
10865
10866 maxlogins = 3;
10867 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
10868 if (sscanf(val, "%30d", &x) == 1) {
10869 maxlogins = x;
10870 } else {
10871 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
10872 }
10873 }
10874
10875 minpassword = MINPASSWORD;
10876 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
10877 if (sscanf(val, "%30d", &x) == 1) {
10878 minpassword = x;
10879 } else {
10880 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
10881 }
10882 }
10883
10884
10885 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
10886 val = "no";
10887 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
10888
10889
10890 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
10891 val = "no";
10892 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
10893
10894 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
10895 ast_debug(1, "VM_CID Internal context string: %s\n", val);
10896 stringp = ast_strdupa(val);
10897 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
10898 if (!ast_strlen_zero(stringp)) {
10899 q = strsep(&stringp, ",");
10900 while ((*q == ' ')||(*q == '\t'))
10901 q++;
10902 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
10903 ast_debug(1,"VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
10904 } else {
10905 cidinternalcontexts[x][0] = '\0';
10906 }
10907 }
10908 }
10909 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
10910 ast_debug(1,"VM Review Option disabled globally\n");
10911 val = "no";
10912 }
10913 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
10914
10915
10916 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
10917 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
10918 val = "no";
10919 } else {
10920 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
10921 }
10922 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
10923 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
10924 ast_debug(1, "VM next message wrap disabled globally\n");
10925 val = "no";
10926 }
10927 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
10928
10929 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
10930 ast_debug(1,"VM Operator break disabled globally\n");
10931 val = "no";
10932 }
10933 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
10934
10935 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
10936 ast_debug(1,"VM CID Info before msg disabled globally\n");
10937 val = "no";
10938 }
10939 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
10940
10941 if (!(val = ast_variable_retrieve(cfg,"general", "sendvoicemail"))){
10942 ast_debug(1,"Send Voicemail msg disabled globally\n");
10943 val = "no";
10944 }
10945 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
10946
10947 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
10948 ast_debug(1,"ENVELOPE before msg enabled globally\n");
10949 val = "yes";
10950 }
10951 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
10952
10953 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
10954 ast_debug(1,"Move Heard enabled globally\n");
10955 val = "yes";
10956 }
10957 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
10958
10959 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
10960 ast_debug(1,"Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
10961 val = "no";
10962 }
10963 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
10964
10965 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
10966 ast_debug(1,"Duration info before msg enabled globally\n");
10967 val = "yes";
10968 }
10969 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
10970
10971 saydurationminfo = 2;
10972 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
10973 if (sscanf(val, "%30d", &x) == 1) {
10974 saydurationminfo = x;
10975 } else {
10976 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
10977 }
10978 }
10979
10980 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
10981 ast_debug(1,"We are not going to skip to the next msg after save/delete\n");
10982 val = "no";
10983 }
10984 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
10985
10986 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
10987 ast_copy_string(dialcontext, val, sizeof(dialcontext));
10988 ast_debug(1, "found dialout context: %s\n", dialcontext);
10989 } else {
10990 dialcontext[0] = '\0';
10991 }
10992
10993 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
10994 ast_copy_string(callcontext, val, sizeof(callcontext));
10995 ast_debug(1, "found callback context: %s\n", callcontext);
10996 } else {
10997 callcontext[0] = '\0';
10998 }
10999
11000 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
11001 ast_copy_string(exitcontext, val, sizeof(exitcontext));
11002 ast_debug(1, "found operator context: %s\n", exitcontext);
11003 } else {
11004 exitcontext[0] = '\0';
11005 }
11006
11007
11008 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
11009 ast_copy_string(vm_password, val, sizeof(vm_password));
11010 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
11011 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
11012 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
11013 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
11014 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
11015 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
11016 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
11017 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
11018 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
11019 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
11020 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
11021 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
11022 }
11023
11024 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
11025 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
11026 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
11027 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
11028 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
11029 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
11030 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
11031 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
11032 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
11033 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
11034
11035 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
11036 val = "no";
11037 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
11038
11039 poll_freq = DEFAULT_POLL_FREQ;
11040 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
11041 if (sscanf(val, "%30u", &poll_freq) != 1) {
11042 poll_freq = DEFAULT_POLL_FREQ;
11043 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
11044 }
11045 }
11046
11047 poll_mailboxes = 0;
11048 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
11049 poll_mailboxes = ast_true(val);
11050
11051 if (ucfg) {
11052 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
11053 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
11054 continue;
11055 if ((current = find_or_create(userscontext, cat))) {
11056 populate_defaults(current);
11057 apply_options_full(current, ast_variable_browse(ucfg, cat));
11058 ast_copy_string(current->context, userscontext, sizeof(current->context));
11059 }
11060 }
11061 ast_config_destroy(ucfg);
11062 }
11063 cat = ast_category_browse(cfg, NULL);
11064 while (cat) {
11065 if (strcasecmp(cat, "general")) {
11066 var = ast_variable_browse(cfg, cat);
11067 if (strcasecmp(cat, "zonemessages")) {
11068
11069 while (var) {
11070 append_mailbox(cat, var->name, var->value);
11071 var = var->next;
11072 }
11073 } else {
11074
11075 while (var) {
11076 struct vm_zone *z;
11077 if ((z = ast_malloc(sizeof(*z)))) {
11078 char *msg_format, *tzone;
11079 msg_format = ast_strdupa(var->value);
11080 tzone = strsep(&msg_format, "|");
11081 if (msg_format) {
11082 ast_copy_string(z->name, var->name, sizeof(z->name));
11083 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
11084 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
11085 AST_LIST_LOCK(&zones);
11086 AST_LIST_INSERT_HEAD(&zones, z, list);
11087 AST_LIST_UNLOCK(&zones);
11088 } else {
11089 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
11090 ast_free(z);
11091 }
11092 } else {
11093 AST_LIST_UNLOCK(&users);
11094 ast_config_destroy(cfg);
11095 return -1;
11096 }
11097 var = var->next;
11098 }
11099 }
11100 }
11101 cat = ast_category_browse(cfg, cat);
11102 }
11103 memset(fromstring, 0, sizeof(fromstring));
11104 memset(pagerfromstring, 0, sizeof(pagerfromstring));
11105 strcpy(charset, "ISO-8859-1");
11106 if (emailbody) {
11107 ast_free(emailbody);
11108 emailbody = NULL;
11109 }
11110 if (emailsubject) {
11111 ast_free(emailsubject);
11112 emailsubject = NULL;
11113 }
11114 if (pagerbody) {
11115 ast_free(pagerbody);
11116 pagerbody = NULL;
11117 }
11118 if (pagersubject) {
11119 ast_free(pagersubject);
11120 pagersubject = NULL;
11121 }
11122 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
11123 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
11124 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
11125 ast_copy_string(fromstring, val, sizeof(fromstring));
11126 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
11127 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
11128 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
11129 ast_copy_string(charset, val, sizeof(charset));
11130 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
11131 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
11132 for (x = 0; x < 4; x++) {
11133 memcpy(&adsifdn[x], &tmpadsi[x], 1);
11134 }
11135 }
11136 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
11137 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
11138 for (x = 0; x < 4; x++) {
11139 memcpy(&adsisec[x], &tmpadsi[x], 1);
11140 }
11141 }
11142 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
11143 if (atoi(val)) {
11144 adsiver = atoi(val);
11145 }
11146 }
11147 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
11148 ast_copy_string(zonetag, val, sizeof(zonetag));
11149 }
11150 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
11151 emailsubject = ast_strdup(val);
11152 }
11153 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
11154 emailbody = substitute_escapes(val);
11155 }
11156 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
11157 pagersubject = ast_strdup(val);
11158 }
11159 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
11160 pagerbody = substitute_escapes(val);
11161 }
11162 AST_LIST_UNLOCK(&users);
11163 ast_config_destroy(cfg);
11164
11165 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
11166 start_poll_thread();
11167 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
11168 stop_poll_thread();;
11169
11170 return 0;
11171 } else {
11172 AST_LIST_UNLOCK(&users);
11173 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
11174 if (ucfg)
11175 ast_config_destroy(ucfg);
11176 return 0;
11177 }
11178 }
11179
11180 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
11181 {
11182 int res = -1;
11183 char dir[PATH_MAX];
11184 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
11185 ast_debug(2, "About to try retrieving name file %s\n", dir);
11186 RETRIEVE(dir, -1, mailbox, context);
11187 if (ast_fileexists(dir, NULL, NULL)) {
11188 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
11189 }
11190 DISPOSE(dir, -1);
11191 return res;
11192 }
11193
11194 static int reload(void)
11195 {
11196 return load_config(1);
11197 }
11198
11199 static int unload_module(void)
11200 {
11201 int res;
11202
11203 res = ast_unregister_application(app);
11204 res |= ast_unregister_application(app2);
11205 res |= ast_unregister_application(app3);
11206 res |= ast_unregister_application(app4);
11207 res |= ast_custom_function_unregister(&mailbox_exists_acf);
11208 res |= ast_manager_unregister("VoicemailUsersList");
11209 ast_cli_unregister_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
11210 ast_uninstall_vm_functions();
11211 ao2_ref(inprocess_container, -1);
11212
11213 if (poll_thread != AST_PTHREADT_NULL)
11214 stop_poll_thread();
11215
11216 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
11217 ast_unload_realtime("voicemail");
11218 ast_unload_realtime("voicemail_data");
11219
11220 free_vm_users();
11221 free_vm_zones();
11222 return res;
11223 }
11224
11225 static int load_module(void)
11226 {
11227 int res;
11228 my_umask = umask(0);
11229 umask(my_umask);
11230
11231 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
11232 return AST_MODULE_LOAD_DECLINE;
11233 }
11234
11235
11236 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
11237
11238 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
11239 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
11240 }
11241
11242 if ((res = load_config(0)))
11243 return res;
11244
11245 res = ast_register_application(app, vm_exec, synopsis_vm, descrip_vm);
11246 res |= ast_register_application(app2, vm_execmain, synopsis_vmain, descrip_vmain);
11247 res |= ast_register_application(app3, vm_box_exists, synopsis_vm_box_exists, descrip_vm_box_exists);
11248 res |= ast_register_application(app4, vmauthenticate, synopsis_vmauthenticate, descrip_vmauthenticate);
11249 res |= ast_custom_function_register(&mailbox_exists_acf);
11250 res |= ast_manager_register("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users, "List All Voicemail User Information");
11251 if (res)
11252 return res;
11253
11254 ast_cli_register_multiple(cli_voicemail, sizeof(cli_voicemail) / sizeof(struct ast_cli_entry));
11255
11256 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
11257 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
11258 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
11259
11260 return res;
11261 }
11262
11263 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
11264 {
11265 int cmd = 0;
11266 char destination[80] = "";
11267 int retries = 0;
11268
11269 if (!num) {
11270 ast_verb(3, "Destination number will be entered manually\n");
11271 while (retries < 3 && cmd != 't') {
11272 destination[1] = '\0';
11273 destination[0] = cmd = ast_play_and_wait(chan,"vm-enter-num-to-call");
11274 if (!cmd)
11275 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
11276 if (!cmd)
11277 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
11278 if (!cmd) {
11279 cmd = ast_waitfordigit(chan, 6000);
11280 if (cmd)
11281 destination[0] = cmd;
11282 }
11283 if (!cmd) {
11284 retries++;
11285 } else {
11286
11287 if (cmd < 0)
11288 return 0;
11289 if (cmd == '*') {
11290 ast_verb(3, "User hit '*' to cancel outgoing call\n");
11291 return 0;
11292 }
11293 if ((cmd = ast_readstring(chan,destination + strlen(destination),sizeof(destination)-1,6000,10000,"#")) < 0)
11294 retries++;
11295 else
11296 cmd = 't';
11297 }
11298 }
11299 if (retries >= 3) {
11300 return 0;
11301 }
11302
11303 } else {
11304 if (option_verbose > 2)
11305 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
11306 ast_copy_string(destination, num, sizeof(destination));
11307 }
11308
11309 if (!ast_strlen_zero(destination)) {
11310 if (destination[strlen(destination) -1 ] == '*')
11311 return 0;
11312 if (option_verbose > 2)
11313 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
11314 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
11315 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
11316 chan->priority = 0;
11317 return 9;
11318 }
11319 return 0;
11320 }
11321
11322
11323
11324
11325
11326
11327
11328
11329
11330
11331
11332
11333
11334
11335 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)
11336 {
11337 int res = 0;
11338 char filename[PATH_MAX];
11339 struct ast_config *msg_cfg = NULL;
11340 const char *origtime, *context;
11341 char *name, *num;
11342 int retries = 0;
11343 char *cid;
11344 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
11345
11346 vms->starting = 0;
11347
11348 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
11349
11350
11351 snprintf(filename,sizeof(filename), "%s.txt", vms->fn);
11352 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
11353 msg_cfg = ast_config_load(filename, config_flags);
11354 DISPOSE(vms->curdir, vms->curmsg);
11355 if (!msg_cfg) {
11356 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
11357 return 0;
11358 }
11359
11360 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
11361 ast_config_destroy(msg_cfg);
11362 return 0;
11363 }
11364
11365 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
11366
11367 context = ast_variable_retrieve(msg_cfg, "message", "context");
11368 if (!strncasecmp("macro",context,5))
11369 context = ast_variable_retrieve(msg_cfg, "message","macrocontext");
11370 switch (option) {
11371 case 3:
11372 if (!res)
11373 res = play_message_datetime(chan, vmu, origtime, filename);
11374 if (!res)
11375 res = play_message_callerid(chan, vms, cid, context, 0);
11376
11377 res = 't';
11378 break;
11379
11380 case 2:
11381
11382 if (ast_strlen_zero(cid))
11383 break;
11384
11385 ast_callerid_parse(cid, &name, &num);
11386 while ((res > -1) && (res != 't')) {
11387 switch (res) {
11388 case '1':
11389 if (num) {
11390
11391 res = dialout(chan, vmu, num, vmu->callback);
11392 if (res) {
11393 ast_config_destroy(msg_cfg);
11394 return 9;
11395 }
11396 } else {
11397 res = '2';
11398 }
11399 break;
11400
11401 case '2':
11402
11403 if (!ast_strlen_zero(vmu->dialout)) {
11404 res = dialout(chan, vmu, NULL, vmu->dialout);
11405 if (res) {
11406 ast_config_destroy(msg_cfg);
11407 return 9;
11408 }
11409 } else {
11410 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
11411 res = ast_play_and_wait(chan, "vm-sorry");
11412 }
11413 ast_config_destroy(msg_cfg);
11414 return res;
11415 case '*':
11416 res = 't';
11417 break;
11418 case '3':
11419 case '4':
11420 case '5':
11421 case '6':
11422 case '7':
11423 case '8':
11424 case '9':
11425 case '0':
11426
11427 res = ast_play_and_wait(chan, "vm-sorry");
11428 retries++;
11429 break;
11430 default:
11431 if (num) {
11432 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
11433 res = ast_play_and_wait(chan, "vm-num-i-have");
11434 if (!res)
11435 res = play_message_callerid(chan, vms, num, vmu->context, 1);
11436 if (!res)
11437 res = ast_play_and_wait(chan, "vm-tocallnum");
11438
11439 if (!ast_strlen_zero(vmu->dialout)) {
11440 if (!res)
11441 res = ast_play_and_wait(chan, "vm-calldiffnum");
11442 }
11443 } else {
11444 res = ast_play_and_wait(chan, "vm-nonumber");
11445 if (!ast_strlen_zero(vmu->dialout)) {
11446 if (!res)
11447 res = ast_play_and_wait(chan, "vm-toenternumber");
11448 }
11449 }
11450 if (!res)
11451 res = ast_play_and_wait(chan, "vm-star-cancel");
11452 if (!res)
11453 res = ast_waitfordigit(chan, 6000);
11454 if (!res) {
11455 retries++;
11456 if (retries > 3)
11457 res = 't';
11458 }
11459 break;
11460
11461 }
11462 if (res == 't')
11463 res = 0;
11464 else if (res == '*')
11465 res = -1;
11466 }
11467 break;
11468
11469 case 1:
11470
11471 if (ast_strlen_zero(cid))
11472 break;
11473
11474 ast_callerid_parse(cid, &name, &num);
11475 if (!num) {
11476 ast_verb(3, "No CID number available, no reply sent\n");
11477 if (!res)
11478 res = ast_play_and_wait(chan, "vm-nonumber");
11479 ast_config_destroy(msg_cfg);
11480 return res;
11481 } else {
11482 struct ast_vm_user vmu2;
11483 if (find_user(&vmu2, vmu->context, num)) {
11484 struct leave_vm_options leave_options;
11485 char mailbox[AST_MAX_EXTENSION * 2 + 2];
11486 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
11487
11488 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
11489
11490 memset(&leave_options, 0, sizeof(leave_options));
11491 leave_options.record_gain = record_gain;
11492 res = leave_voicemail(chan, mailbox, &leave_options);
11493 if (!res)
11494 res = 't';
11495 ast_config_destroy(msg_cfg);
11496 return res;
11497 } else {
11498
11499 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
11500 ast_play_and_wait(chan, "vm-nobox");
11501 res = 't';
11502 ast_config_destroy(msg_cfg);
11503 return res;
11504 }
11505 }
11506 res = 0;
11507
11508 break;
11509 }
11510
11511 #ifndef IMAP_STORAGE
11512 ast_config_destroy(msg_cfg);
11513
11514 if (!res) {
11515 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
11516 vms->heard[msg] = 1;
11517 res = wait_file(chan, vms, vms->fn);
11518 }
11519 #endif
11520 return res;
11521 }
11522
11523 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
11524 int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
11525 signed char record_gain, struct vm_state *vms, char *flag)
11526 {
11527
11528 int res = 0;
11529 int cmd = 0;
11530 int max_attempts = 3;
11531 int attempts = 0;
11532 int recorded = 0;
11533 int msg_exists = 0;
11534 signed char zero_gain = 0;
11535 char tempfile[PATH_MAX];
11536 char *acceptdtmf = "#";
11537 char *canceldtmf = "";
11538
11539
11540
11541
11542 if (duration == NULL) {
11543 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
11544 return -1;
11545 }
11546
11547 if (!outsidecaller)
11548 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
11549 else
11550 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
11551
11552 cmd = '3';
11553
11554 while ((cmd >= 0) && (cmd != 't')) {
11555 switch (cmd) {
11556 case '1':
11557 if (!msg_exists) {
11558
11559 cmd = '3';
11560 break;
11561 } else {
11562
11563 ast_verb(3, "Saving message as is\n");
11564 if (!outsidecaller)
11565 ast_filerename(tempfile, recordfile, NULL);
11566 ast_stream_and_wait(chan, "vm-msgsaved", "");
11567 if (!outsidecaller) {
11568
11569 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
11570 DISPOSE(recordfile, -1);
11571 }
11572 cmd = 't';
11573 return res;
11574 }
11575 case '2':
11576
11577 ast_verb(3, "Reviewing the message\n");
11578 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
11579 break;
11580 case '3':
11581 msg_exists = 0;
11582
11583 if (recorded == 1)
11584 ast_verb(3, "Re-recording the message\n");
11585 else
11586 ast_verb(3, "Recording the message\n");
11587
11588 if (recorded && outsidecaller) {
11589 cmd = ast_play_and_wait(chan, INTRO);
11590 cmd = ast_play_and_wait(chan, "beep");
11591 }
11592 recorded = 1;
11593
11594 if (record_gain)
11595 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
11596 if (ast_test_flag(vmu, VM_OPERATOR))
11597 canceldtmf = "0";
11598 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
11599 if (record_gain)
11600 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
11601 if (cmd == -1) {
11602
11603 if (!outsidecaller) {
11604
11605 ast_filedelete(tempfile, NULL);
11606 }
11607 return cmd;
11608 }
11609 if (cmd == '0') {
11610 break;
11611 } else if (cmd == '*') {
11612 break;
11613 #if 0
11614 } else if (vmu->review && (*duration < 5)) {
11615
11616 ast_verb(3, "Message too short\n");
11617 cmd = ast_play_and_wait(chan, "vm-tooshort");
11618 cmd = ast_filedelete(tempfile, NULL);
11619 break;
11620 } else if (vmu->review && (cmd == 2 && *duration < (maxsilence + 3))) {
11621
11622 ast_verb(3, "Nothing recorded\n");
11623 cmd = ast_filedelete(tempfile, NULL);
11624 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
11625 if (!cmd)
11626 cmd = ast_play_and_wait(chan, "vm-speakup");
11627 break;
11628 #endif
11629 } else {
11630
11631 msg_exists = 1;
11632 cmd = 0;
11633 }
11634 break;
11635 case '4':
11636 if (outsidecaller) {
11637
11638 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
11639 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
11640 ast_debug(1000, "This message is too urgent!\n");
11641 res = ast_play_and_wait(chan, "vm-marked-urgent");
11642 strcpy(flag, "Urgent");
11643 } else if (flag) {
11644 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
11645 res = ast_play_and_wait(chan, "vm-urgent-removed");
11646 strcpy(flag, "");
11647 } else {
11648 ast_play_and_wait(chan, "vm-sorry");
11649 }
11650 cmd = 0;
11651 } else {
11652 cmd = ast_play_and_wait(chan, "vm-sorry");
11653 }
11654 break;
11655 case '5':
11656 case '6':
11657 case '7':
11658 case '8':
11659 case '9':
11660 case '*':
11661 case '#':
11662 cmd = ast_play_and_wait(chan, "vm-sorry");
11663 break;
11664 #if 0
11665
11666
11667 case '*':
11668
11669 cmd = ast_play_and_wait(chan, "vm-deleted");
11670 cmd = ast_filedelete(tempfile, NULL);
11671 if (outsidecaller) {
11672 res = vm_exec(chan, NULL);
11673 return res;
11674 }
11675 else
11676 return 1;
11677 #endif
11678 case '0':
11679 if (!ast_test_flag(vmu, VM_OPERATOR) || !outsidecaller) {
11680 cmd = ast_play_and_wait(chan, "vm-sorry");
11681 break;
11682 }
11683 if (msg_exists || recorded) {
11684 cmd = ast_play_and_wait(chan, "vm-saveoper");
11685 if (!cmd)
11686 cmd = ast_waitfordigit(chan, 3000);
11687 if (cmd == '1') {
11688 ast_play_and_wait(chan, "vm-msgsaved");
11689 cmd = '0';
11690 } else if (cmd == '4') {
11691 if (flag) {
11692 ast_play_and_wait(chan, "vm-marked-urgent");
11693 strcpy(flag, "Urgent");
11694 }
11695 ast_play_and_wait(chan, "vm-msgsaved");
11696 cmd = '0';
11697 } else {
11698 ast_play_and_wait(chan, "vm-deleted");
11699 DELETE(recordfile, -1, recordfile, vmu);
11700 cmd = '0';
11701 }
11702 }
11703 return cmd;
11704 default:
11705
11706
11707
11708 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
11709 return cmd;
11710 if (msg_exists) {
11711 cmd = ast_play_and_wait(chan, "vm-review");
11712 if (!cmd && outsidecaller) {
11713 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
11714 cmd = ast_play_and_wait(chan, "vm-review-urgent");
11715 } else if (flag) {
11716 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
11717 }
11718 }
11719 } else {
11720 cmd = ast_play_and_wait(chan, "vm-torerecord");
11721 if (!cmd)
11722 cmd = ast_waitfordigit(chan, 600);
11723 }
11724
11725 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
11726 cmd = ast_play_and_wait(chan, "vm-reachoper");
11727 if (!cmd)
11728 cmd = ast_waitfordigit(chan, 600);
11729 }
11730 #if 0
11731 if (!cmd)
11732 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
11733 #endif
11734 if (!cmd)
11735 cmd = ast_waitfordigit(chan, 6000);
11736 if (!cmd) {
11737 attempts++;
11738 }
11739 if (attempts > max_attempts) {
11740 cmd = 't';
11741 }
11742 }
11743 }
11744 if (cmd == 't')
11745 cmd = 0;
11746 else if (outsidecaller)
11747 ast_play_and_wait(chan, "vm-goodbye");
11748 return cmd;
11749 }
11750
11751
11752
11753
11754
11755 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
11756 .load = load_module,
11757 .unload = unload_module,
11758 .reload = reload,
11759 );