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