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 #include "asterisk.h"
00066
00067 #ifdef IMAP_STORAGE
00068 #include <ctype.h>
00069 #include <signal.h>
00070 #include <pwd.h>
00071 #ifdef USE_SYSTEM_IMAP
00072 #include <imap/c-client.h>
00073 #include <imap/imap4r1.h>
00074 #include <imap/linkage.h>
00075 #elif defined (USE_SYSTEM_CCLIENT)
00076 #include <c-client/c-client.h>
00077 #include <c-client/imap4r1.h>
00078 #include <c-client/linkage.h>
00079 #else
00080 #include "c-client.h"
00081 #include "imap4r1.h"
00082 #include "linkage.h"
00083 #endif
00084 #endif
00085
00086 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369652 $")
00087
00088 #include "asterisk/paths.h"
00089 #include <sys/time.h>
00090 #include <sys/stat.h>
00091 #include <sys/mman.h>
00092 #include <time.h>
00093 #include <dirent.h>
00094 #if defined(__FreeBSD__) || defined(__OpenBSD__)
00095 #include <sys/wait.h>
00096 #endif
00097
00098 #include "asterisk/logger.h"
00099 #include "asterisk/lock.h"
00100 #include "asterisk/file.h"
00101 #include "asterisk/channel.h"
00102 #include "asterisk/pbx.h"
00103 #include "asterisk/config.h"
00104 #include "asterisk/say.h"
00105 #include "asterisk/module.h"
00106 #include "asterisk/adsi.h"
00107 #include "asterisk/app.h"
00108 #include "asterisk/manager.h"
00109 #include "asterisk/dsp.h"
00110 #include "asterisk/localtime.h"
00111 #include "asterisk/cli.h"
00112 #include "asterisk/utils.h"
00113 #include "asterisk/stringfields.h"
00114 #include "asterisk/smdi.h"
00115 #include "asterisk/astobj2.h"
00116 #include "asterisk/event.h"
00117 #include "asterisk/taskprocessor.h"
00118 #include "asterisk/test.h"
00119
00120 #ifdef ODBC_STORAGE
00121 #include "asterisk/res_odbc.h"
00122 #endif
00123
00124 #ifdef IMAP_STORAGE
00125 #include "asterisk/threadstorage.h"
00126 #endif
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
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 #ifdef IMAP_STORAGE
00367 static char imapserver[48];
00368 static char imapport[8];
00369 static char imapflags[128];
00370 static char imapfolder[64];
00371 static char imapparentfolder[64] = "\0";
00372 static char greetingfolder[64];
00373 static char authuser[32];
00374 static char authpassword[42];
00375 static int imapversion = 1;
00376
00377 static int expungeonhangup = 1;
00378 static int imapgreetings = 0;
00379 static char delimiter = '\0';
00380
00381 struct vm_state;
00382 struct ast_vm_user;
00383
00384 AST_THREADSTORAGE(ts_vmstate);
00385
00386
00387 static int init_mailstream(struct vm_state *vms, int box);
00388 static void write_file(char *filename, char *buffer, unsigned long len);
00389 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00390 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00391 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00392 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00393 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00394 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00395 static void vmstate_insert(struct vm_state *vms);
00396 static void vmstate_delete(struct vm_state *vms);
00397 static void set_update(MAILSTREAM * stream);
00398 static void init_vm_state(struct vm_state *vms);
00399 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
00400 static void get_mailbox_delimiter(MAILSTREAM *stream);
00401 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00402 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00403 static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag);
00404 static void update_messages_by_imapuser(const char *user, unsigned long number);
00405 static int vm_delete(char *file);
00406
00407 static int imap_remove_file (char *dir, int msgnum);
00408 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00409 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00410 static void check_quota(struct vm_state *vms, char *mailbox);
00411 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00412 struct vmstate {
00413 struct vm_state *vms;
00414 AST_LIST_ENTRY(vmstate) list;
00415 };
00416
00417 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00418
00419 #endif
00420
00421 #define SMDI_MWI_WAIT_TIMEOUT 1000
00422
00423 #define COMMAND_TIMEOUT 5000
00424
00425 #define VOICEMAIL_DIR_MODE 0777
00426 #define VOICEMAIL_FILE_MODE 0666
00427 #define CHUNKSIZE 65536
00428
00429 #define VOICEMAIL_CONFIG "voicemail.conf"
00430 #define ASTERISK_USERNAME "asterisk"
00431
00432
00433
00434
00435 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00436 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00437 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00438 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00439 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00440 #define VALID_DTMF "1234567890*#"
00441
00442
00443
00444 #define SENDMAIL "/usr/sbin/sendmail -t"
00445
00446 #define INTRO "vm-intro"
00447
00448 #define MAXMSG 100
00449 #define MAXMSGLIMIT 9999
00450
00451 #define MINPASSWORD 0
00452
00453 #define BASELINELEN 72
00454 #define BASEMAXINLINE 256
00455 #ifdef IMAP_STORAGE
00456 #define ENDL "\r\n"
00457 #else
00458 #define ENDL "\n"
00459 #endif
00460
00461 #define MAX_DATETIME_FORMAT 512
00462 #define MAX_NUM_CID_CONTEXTS 10
00463
00464 #define VM_REVIEW (1 << 0)
00465 #define VM_OPERATOR (1 << 1)
00466 #define VM_SAYCID (1 << 2)
00467 #define VM_SVMAIL (1 << 3)
00468 #define VM_ENVELOPE (1 << 4)
00469 #define VM_SAYDURATION (1 << 5)
00470 #define VM_SKIPAFTERCMD (1 << 6)
00471 #define VM_FORCENAME (1 << 7)
00472 #define VM_FORCEGREET (1 << 8)
00473 #define VM_PBXSKIP (1 << 9)
00474 #define VM_DIRECFORWARD (1 << 10)
00475 #define VM_ATTACH (1 << 11)
00476 #define VM_DELETE (1 << 12)
00477 #define VM_ALLOCED (1 << 13)
00478 #define VM_SEARCH (1 << 14)
00479 #define VM_TEMPGREETWARN (1 << 15)
00480 #define VM_MOVEHEARD (1 << 16)
00481 #define VM_MESSAGEWRAP (1 << 17)
00482 #define VM_FWDURGAUTO (1 << 18)
00483 #define ERROR_LOCK_PATH -100
00484 #define OPERATOR_EXIT 300
00485
00486
00487 enum vm_box {
00488 NEW_FOLDER,
00489 OLD_FOLDER,
00490 WORK_FOLDER,
00491 FAMILY_FOLDER,
00492 FRIENDS_FOLDER,
00493 GREETINGS_FOLDER
00494 };
00495
00496 enum vm_option_flags {
00497 OPT_SILENT = (1 << 0),
00498 OPT_BUSY_GREETING = (1 << 1),
00499 OPT_UNAVAIL_GREETING = (1 << 2),
00500 OPT_RECORDGAIN = (1 << 3),
00501 OPT_PREPEND_MAILBOX = (1 << 4),
00502 OPT_AUTOPLAY = (1 << 6),
00503 OPT_DTMFEXIT = (1 << 7),
00504 OPT_MESSAGE_Urgent = (1 << 8),
00505 OPT_MESSAGE_PRIORITY = (1 << 9)
00506 };
00507
00508 enum vm_option_args {
00509 OPT_ARG_RECORDGAIN = 0,
00510 OPT_ARG_PLAYFOLDER = 1,
00511 OPT_ARG_DTMFEXIT = 2,
00512
00513 OPT_ARG_ARRAY_SIZE = 3,
00514 };
00515
00516 enum vm_passwordlocation {
00517 OPT_PWLOC_VOICEMAILCONF = 0,
00518 OPT_PWLOC_SPOOLDIR = 1,
00519 OPT_PWLOC_USERSCONF = 2,
00520 };
00521
00522 AST_APP_OPTIONS(vm_app_options, {
00523 AST_APP_OPTION('s', OPT_SILENT),
00524 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00525 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00526 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00527 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00528 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00529 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00530 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
00531 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
00532 });
00533
00534 static int load_config(int reload);
00535 #ifdef TEST_FRAMEWORK
00536 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00537 #endif
00538 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623 struct baseio {
00624 int iocp;
00625 int iolen;
00626 int linelength;
00627 int ateof;
00628 unsigned char iobuf[BASEMAXINLINE];
00629 };
00630
00631
00632
00633 struct ast_vm_user {
00634 char context[AST_MAX_CONTEXT];
00635 char mailbox[AST_MAX_EXTENSION];
00636 char password[80];
00637 char fullname[80];
00638 char email[80];
00639 char *emailsubject;
00640 char *emailbody;
00641 char pager[80];
00642 char serveremail[80];
00643 char mailcmd[160];
00644 char language[MAX_LANGUAGE];
00645 char zonetag[80];
00646 char locale[20];
00647 char callback[80];
00648 char dialout[80];
00649 char uniqueid[80];
00650 char exit[80];
00651 char attachfmt[20];
00652 unsigned int flags;
00653 int saydurationm;
00654 int minsecs;
00655 int maxmsg;
00656 int maxdeletedmsg;
00657 int maxsecs;
00658 int passwordlocation;
00659 #ifdef IMAP_STORAGE
00660 char imapuser[80];
00661 char imappassword[80];
00662 char imapfolder[64];
00663 char imapvmshareid[80];
00664 int imapversion;
00665 #endif
00666 double volgain;
00667 AST_LIST_ENTRY(ast_vm_user) list;
00668 };
00669
00670
00671 struct vm_zone {
00672 AST_LIST_ENTRY(vm_zone) list;
00673 char name[80];
00674 char timezone[80];
00675 char msg_format[512];
00676 };
00677
00678 #define VMSTATE_MAX_MSG_ARRAY 256
00679
00680
00681 struct vm_state {
00682 char curbox[80];
00683 char username[80];
00684 char context[80];
00685 char curdir[PATH_MAX];
00686 char vmbox[PATH_MAX];
00687 char fn[PATH_MAX];
00688 char intro[PATH_MAX];
00689 int *deleted;
00690 int *heard;
00691 int dh_arraysize;
00692 int curmsg;
00693 int lastmsg;
00694 int newmessages;
00695 int oldmessages;
00696 int urgentmessages;
00697 int starting;
00698 int repeats;
00699 #ifdef IMAP_STORAGE
00700 ast_mutex_t lock;
00701 int updated;
00702 long msgArray[VMSTATE_MAX_MSG_ARRAY];
00703 MAILSTREAM *mailstream;
00704 int vmArrayIndex;
00705 char imapuser[80];
00706 char imapfolder[64];
00707 int imapversion;
00708 int interactive;
00709 char introfn[PATH_MAX];
00710 unsigned int quota_limit;
00711 unsigned int quota_usage;
00712 struct vm_state *persist_vms;
00713 #endif
00714 };
00715
00716 #ifdef ODBC_STORAGE
00717 static char odbc_database[80];
00718 static char odbc_table[80];
00719 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00720 #define DISPOSE(a,b) remove_file(a,b)
00721 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00722 #define EXISTS(a,b,c,d) (message_exists(a,b))
00723 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00724 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00725 #define DELETE(a,b,c,d) (delete_file(a,b))
00726 #else
00727 #ifdef IMAP_STORAGE
00728 #define DISPOSE(a,b) (imap_remove_file(a,b))
00729 #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))
00730 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00731 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00732 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00733 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00734 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00735 #else
00736 #define RETRIEVE(a,b,c,d)
00737 #define DISPOSE(a,b)
00738 #define STORE(a,b,c,d,e,f,g,h,i,j)
00739 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00740 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00741 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00742 #define DELETE(a,b,c,d) (vm_delete(c))
00743 #endif
00744 #endif
00745
00746 static char VM_SPOOL_DIR[PATH_MAX];
00747
00748 static char ext_pass_cmd[128];
00749 static char ext_pass_check_cmd[128];
00750
00751 static int my_umask;
00752
00753 #define PWDCHANGE_INTERNAL (1 << 1)
00754 #define PWDCHANGE_EXTERNAL (1 << 2)
00755 static int pwdchange = PWDCHANGE_INTERNAL;
00756
00757 #ifdef ODBC_STORAGE
00758 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00759 #else
00760 # ifdef IMAP_STORAGE
00761 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00762 # else
00763 # define tdesc "Comedian Mail (Voicemail System)"
00764 # endif
00765 #endif
00766
00767 static char userscontext[AST_MAX_EXTENSION] = "default";
00768
00769 static char *addesc = "Comedian Mail";
00770
00771
00772 static char *app = "VoiceMail";
00773
00774
00775 static char *app2 = "VoiceMailMain";
00776
00777 static char *app3 = "MailboxExists";
00778 static char *app4 = "VMAuthenticate";
00779
00780 static char *sayname_app = "VMSayName";
00781
00782 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00783 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00784 static char zonetag[80];
00785 static char locale[20];
00786 static int maxsilence;
00787 static int maxmsg;
00788 static int maxdeletedmsg;
00789 static int silencethreshold = 128;
00790 static char serveremail[80];
00791 static char mailcmd[160];
00792 static char externnotify[160];
00793 static struct ast_smdi_interface *smdi_iface = NULL;
00794 static char vmfmts[80];
00795 static double volgain;
00796 static int vmminsecs;
00797 static int vmmaxsecs;
00798 static int maxgreet;
00799 static int skipms;
00800 static int maxlogins;
00801 static int minpassword;
00802 static int passwordlocation;
00803
00804
00805
00806 static unsigned int poll_mailboxes;
00807
00808
00809 static unsigned int poll_freq;
00810
00811 #define DEFAULT_POLL_FREQ 30
00812
00813 AST_MUTEX_DEFINE_STATIC(poll_lock);
00814 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00815 static pthread_t poll_thread = AST_PTHREADT_NULL;
00816 static unsigned char poll_thread_run;
00817
00818
00819 static struct ast_event_sub *mwi_sub_sub;
00820
00821 static struct ast_event_sub *mwi_unsub_sub;
00822
00823
00824
00825
00826
00827
00828
00829
00830 struct mwi_sub {
00831 AST_RWLIST_ENTRY(mwi_sub) entry;
00832 int old_urgent;
00833 int old_new;
00834 int old_old;
00835 uint32_t uniqueid;
00836 char mailbox[1];
00837 };
00838
00839 struct mwi_sub_task {
00840 const char *mailbox;
00841 const char *context;
00842 uint32_t uniqueid;
00843 };
00844
00845 static struct ast_taskprocessor *mwi_subscription_tps;
00846
00847 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00848
00849
00850 static char listen_control_forward_key[12];
00851 static char listen_control_reverse_key[12];
00852 static char listen_control_pause_key[12];
00853 static char listen_control_restart_key[12];
00854 static char listen_control_stop_key[12];
00855
00856
00857 static char vm_password[80] = "vm-password";
00858 static char vm_newpassword[80] = "vm-newpassword";
00859 static char vm_passchanged[80] = "vm-passchanged";
00860 static char vm_reenterpassword[80] = "vm-reenterpassword";
00861 static char vm_mismatch[80] = "vm-mismatch";
00862 static char vm_invalid_password[80] = "vm-invalid-password";
00863 static char vm_pls_try_again[80] = "vm-pls-try-again";
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875 static char vm_prepend_timeout[80] = "vm-then-pound";
00876
00877 static struct ast_flags globalflags = {0};
00878
00879 static int saydurationminfo;
00880
00881 static char dialcontext[AST_MAX_CONTEXT] = "";
00882 static char callcontext[AST_MAX_CONTEXT] = "";
00883 static char exitcontext[AST_MAX_CONTEXT] = "";
00884
00885 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00886
00887
00888 static char *emailbody = NULL;
00889 static char *emailsubject = NULL;
00890 static char *pagerbody = NULL;
00891 static char *pagersubject = NULL;
00892 static char fromstring[100];
00893 static char pagerfromstring[100];
00894 static char charset[32] = "ISO-8859-1";
00895
00896 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00897 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00898 static int adsiver = 1;
00899 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00900 static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
00901
00902
00903 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00904 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);
00905 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00906 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00907 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
00908 signed char record_gain, struct vm_state *vms, char *flag);
00909 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00910 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00911 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);
00912 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);
00913 static void apply_options(struct ast_vm_user *vmu, const char *options);
00914 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);
00915 static int is_valid_dtmf(const char *key);
00916 static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
00917 static int write_password_to_file(const char *secretfn, const char *password);
00918 static const char *substitute_escapes(const char *value);
00919 static void free_user(struct ast_vm_user *vmu);
00920
00921 struct ao2_container *inprocess_container;
00922
00923 struct inprocess {
00924 int count;
00925 char *context;
00926 char mailbox[0];
00927 };
00928
00929 static int inprocess_hash_fn(const void *obj, const int flags)
00930 {
00931 const struct inprocess *i = obj;
00932 return atoi(i->mailbox);
00933 }
00934
00935 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00936 {
00937 struct inprocess *i = obj, *j = arg;
00938 if (strcmp(i->mailbox, j->mailbox)) {
00939 return 0;
00940 }
00941 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00942 }
00943
00944 static int inprocess_count(const char *context, const char *mailbox, int delta)
00945 {
00946 struct inprocess *i, *arg = alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00947 arg->context = arg->mailbox + strlen(mailbox) + 1;
00948 strcpy(arg->mailbox, mailbox);
00949 strcpy(arg->context, context);
00950 ao2_lock(inprocess_container);
00951 if ((i = ao2_find(inprocess_container, arg, 0))) {
00952 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00953 ao2_unlock(inprocess_container);
00954 ao2_ref(i, -1);
00955 return ret;
00956 }
00957 if (delta < 0) {
00958 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
00959 }
00960 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00961 ao2_unlock(inprocess_container);
00962 return 0;
00963 }
00964 i->context = i->mailbox + strlen(mailbox) + 1;
00965 strcpy(i->mailbox, mailbox);
00966 strcpy(i->context, context);
00967 i->count = delta;
00968 ao2_link(inprocess_container, i);
00969 ao2_unlock(inprocess_container);
00970 ao2_ref(i, -1);
00971 return 0;
00972 }
00973
00974 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00975 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00976 #endif
00977
00978
00979
00980
00981
00982
00983
00984 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00985 {
00986 char *bufptr = buf;
00987 for (; *input; input++) {
00988 if (*input < 32) {
00989 continue;
00990 }
00991 *bufptr++ = *input;
00992 if (bufptr == buf + buflen - 1) {
00993 break;
00994 }
00995 }
00996 *bufptr = '\0';
00997 return buf;
00998 }
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014 static void populate_defaults(struct ast_vm_user *vmu)
01015 {
01016 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
01017 vmu->passwordlocation = passwordlocation;
01018 if (saydurationminfo) {
01019 vmu->saydurationm = saydurationminfo;
01020 }
01021 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
01022 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
01023 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
01024 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
01025 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
01026 if (vmminsecs) {
01027 vmu->minsecs = vmminsecs;
01028 }
01029 if (vmmaxsecs) {
01030 vmu->maxsecs = vmmaxsecs;
01031 }
01032 if (maxmsg) {
01033 vmu->maxmsg = maxmsg;
01034 }
01035 if (maxdeletedmsg) {
01036 vmu->maxdeletedmsg = maxdeletedmsg;
01037 }
01038 vmu->volgain = volgain;
01039 ast_free(vmu->emailsubject);
01040 vmu->emailsubject = NULL;
01041 ast_free(vmu->emailbody);
01042 vmu->emailbody = NULL;
01043 #ifdef IMAP_STORAGE
01044 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
01045 #endif
01046 }
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
01057 {
01058 int x;
01059 if (!strcasecmp(var, "attach")) {
01060 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
01061 } else if (!strcasecmp(var, "attachfmt")) {
01062 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
01063 } else if (!strcasecmp(var, "serveremail")) {
01064 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
01065 } else if (!strcasecmp(var, "emailbody")) {
01066 vmu->emailbody = ast_strdup(substitute_escapes(value));
01067 } else if (!strcasecmp(var, "emailsubject")) {
01068 vmu->emailsubject = ast_strdup(substitute_escapes(value));
01069 } else if (!strcasecmp(var, "language")) {
01070 ast_copy_string(vmu->language, value, sizeof(vmu->language));
01071 } else if (!strcasecmp(var, "tz")) {
01072 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
01073 } else if (!strcasecmp(var, "locale")) {
01074 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
01075 #ifdef IMAP_STORAGE
01076 } else if (!strcasecmp(var, "imapuser")) {
01077 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
01078 vmu->imapversion = imapversion;
01079 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
01080 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
01081 vmu->imapversion = imapversion;
01082 } else if (!strcasecmp(var, "imapfolder")) {
01083 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
01084 } else if (!strcasecmp(var, "imapvmshareid")) {
01085 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
01086 vmu->imapversion = imapversion;
01087 #endif
01088 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
01089 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
01090 } else if (!strcasecmp(var, "saycid")){
01091 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
01092 } else if (!strcasecmp(var, "sendvoicemail")){
01093 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
01094 } else if (!strcasecmp(var, "review")){
01095 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
01096 } else if (!strcasecmp(var, "tempgreetwarn")){
01097 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
01098 } else if (!strcasecmp(var, "messagewrap")){
01099 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
01100 } else if (!strcasecmp(var, "operator")) {
01101 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
01102 } else if (!strcasecmp(var, "envelope")){
01103 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
01104 } else if (!strcasecmp(var, "moveheard")){
01105 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
01106 } else if (!strcasecmp(var, "sayduration")){
01107 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
01108 } else if (!strcasecmp(var, "saydurationm")){
01109 if (sscanf(value, "%30d", &x) == 1) {
01110 vmu->saydurationm = x;
01111 } else {
01112 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
01113 }
01114 } else if (!strcasecmp(var, "forcename")){
01115 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
01116 } else if (!strcasecmp(var, "forcegreetings")){
01117 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
01118 } else if (!strcasecmp(var, "callback")) {
01119 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
01120 } else if (!strcasecmp(var, "dialout")) {
01121 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
01122 } else if (!strcasecmp(var, "exitcontext")) {
01123 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
01124 } else if (!strcasecmp(var, "minsecs")) {
01125 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
01126 vmu->minsecs = x;
01127 } else {
01128 ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
01129 vmu->minsecs = vmminsecs;
01130 }
01131 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
01132 vmu->maxsecs = atoi(value);
01133 if (vmu->maxsecs <= 0) {
01134 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
01135 vmu->maxsecs = vmmaxsecs;
01136 } else {
01137 vmu->maxsecs = atoi(value);
01138 }
01139 if (!strcasecmp(var, "maxmessage"))
01140 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
01141 } else if (!strcasecmp(var, "maxmsg")) {
01142 vmu->maxmsg = atoi(value);
01143
01144 if (vmu->maxmsg < 0) {
01145 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
01146 vmu->maxmsg = MAXMSG;
01147 } else if (vmu->maxmsg > MAXMSGLIMIT) {
01148 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
01149 vmu->maxmsg = MAXMSGLIMIT;
01150 }
01151 } else if (!strcasecmp(var, "nextaftercmd")) {
01152 ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
01153 } else if (!strcasecmp(var, "backupdeleted")) {
01154 if (sscanf(value, "%30d", &x) == 1)
01155 vmu->maxdeletedmsg = x;
01156 else if (ast_true(value))
01157 vmu->maxdeletedmsg = MAXMSG;
01158 else
01159 vmu->maxdeletedmsg = 0;
01160
01161 if (vmu->maxdeletedmsg < 0) {
01162 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
01163 vmu->maxdeletedmsg = MAXMSG;
01164 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
01165 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
01166 vmu->maxdeletedmsg = MAXMSGLIMIT;
01167 }
01168 } else if (!strcasecmp(var, "volgain")) {
01169 sscanf(value, "%30lf", &vmu->volgain);
01170 } else if (!strcasecmp(var, "passwordlocation")) {
01171 if (!strcasecmp(value, "spooldir")) {
01172 vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
01173 } else {
01174 vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
01175 }
01176 } else if (!strcasecmp(var, "options")) {
01177 apply_options(vmu, value);
01178 }
01179 }
01180
01181 static char *vm_check_password_shell(char *command, char *buf, size_t len)
01182 {
01183 int fds[2], pid = 0;
01184
01185 memset(buf, 0, len);
01186
01187 if (pipe(fds)) {
01188 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
01189 } else {
01190
01191 pid = ast_safe_fork(0);
01192
01193 if (pid < 0) {
01194
01195 close(fds[0]);
01196 close(fds[1]);
01197 snprintf(buf, len, "FAILURE: Fork failed");
01198 } else if (pid) {
01199
01200 close(fds[1]);
01201 if (read(fds[0], buf, len) < 0) {
01202 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01203 }
01204 close(fds[0]);
01205 } else {
01206
01207 AST_DECLARE_APP_ARGS(arg,
01208 AST_APP_ARG(v)[20];
01209 );
01210 char *mycmd = ast_strdupa(command);
01211
01212 close(fds[0]);
01213 dup2(fds[1], STDOUT_FILENO);
01214 close(fds[1]);
01215 ast_close_fds_above_n(STDOUT_FILENO);
01216
01217 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
01218
01219 execv(arg.v[0], arg.v);
01220 printf("FAILURE: %s", strerror(errno));
01221 _exit(0);
01222 }
01223 }
01224 return buf;
01225 }
01226
01227
01228
01229
01230
01231
01232
01233
01234 static int check_password(struct ast_vm_user *vmu, char *password)
01235 {
01236
01237 if (strlen(password) < minpassword)
01238 return 1;
01239
01240 if (!ast_strlen_zero(password) && password[0] == '*')
01241 return 1;
01242 if (!ast_strlen_zero(ext_pass_check_cmd)) {
01243 char cmd[255], buf[255];
01244
01245 ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
01246
01247 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01248 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01249 ast_debug(5, "Result: %s\n", buf);
01250 if (!strncasecmp(buf, "VALID", 5)) {
01251 ast_debug(3, "Passed password check: '%s'\n", buf);
01252 return 0;
01253 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01254 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01255 return 0;
01256 } else {
01257 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01258 return 1;
01259 }
01260 }
01261 }
01262 return 0;
01263 }
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01276 {
01277 int res = -1;
01278 if (!strcmp(vmu->password, password)) {
01279
01280 return 0;
01281 }
01282
01283 if (strlen(password) > 10) {
01284 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01285 }
01286 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
01287 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
01288 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01289 res = 0;
01290 }
01291 return res;
01292 }
01293
01294
01295
01296
01297 static void apply_options(struct ast_vm_user *vmu, const char *options)
01298 {
01299 char *stringp;
01300 char *s;
01301 char *var, *value;
01302 stringp = ast_strdupa(options);
01303 while ((s = strsep(&stringp, "|"))) {
01304 value = s;
01305 if ((var = strsep(&value, "=")) && value) {
01306 apply_option(vmu, var, value);
01307 }
01308 }
01309 }
01310
01311
01312
01313
01314
01315
01316 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01317 {
01318 for (; var; var = var->next) {
01319 if (!strcasecmp(var->name, "vmsecret")) {
01320 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01321 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) {
01322 if (ast_strlen_zero(retval->password)) {
01323 if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
01324 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
01325 "\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
01326 } else {
01327 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01328 }
01329 }
01330 } else if (!strcasecmp(var->name, "uniqueid")) {
01331 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
01332 } else if (!strcasecmp(var->name, "pager")) {
01333 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
01334 } else if (!strcasecmp(var->name, "email")) {
01335 ast_copy_string(retval->email, var->value, sizeof(retval->email));
01336 } else if (!strcasecmp(var->name, "fullname")) {
01337 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
01338 } else if (!strcasecmp(var->name, "context")) {
01339 ast_copy_string(retval->context, var->value, sizeof(retval->context));
01340 } else if (!strcasecmp(var->name, "emailsubject")) {
01341 ast_free(retval->emailsubject);
01342 retval->emailsubject = ast_strdup(substitute_escapes(var->value));
01343 } else if (!strcasecmp(var->name, "emailbody")) {
01344 ast_free(retval->emailbody);
01345 retval->emailbody = ast_strdup(substitute_escapes(var->value));
01346 #ifdef IMAP_STORAGE
01347 } else if (!strcasecmp(var->name, "imapuser")) {
01348 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
01349 retval->imapversion = imapversion;
01350 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
01351 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
01352 retval->imapversion = imapversion;
01353 } else if (!strcasecmp(var->name, "imapfolder")) {
01354 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
01355 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01356 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01357 retval->imapversion = imapversion;
01358 #endif
01359 } else
01360 apply_option(retval, var->name, var->value);
01361 }
01362 }
01363
01364
01365
01366
01367
01368
01369
01370
01371 static int is_valid_dtmf(const char *key)
01372 {
01373 int i;
01374 char *local_key = ast_strdupa(key);
01375
01376 for (i = 0; i < strlen(key); ++i) {
01377 if (!strchr(VALID_DTMF, *local_key)) {
01378 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01379 return 0;
01380 }
01381 local_key++;
01382 }
01383 return 1;
01384 }
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01397 {
01398 struct ast_variable *var;
01399 struct ast_vm_user *retval;
01400
01401 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01402 if (!ivm)
01403 ast_set_flag(retval, VM_ALLOCED);
01404 else
01405 memset(retval, 0, sizeof(*retval));
01406 if (mailbox)
01407 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01408 populate_defaults(retval);
01409 if (!context && ast_test_flag((&globalflags), VM_SEARCH))
01410 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01411 else
01412 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01413 if (var) {
01414 apply_options_full(retval, var);
01415 ast_variables_destroy(var);
01416 } else {
01417 if (!ivm)
01418 free_user(retval);
01419 retval = NULL;
01420 }
01421 }
01422 return retval;
01423 }
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01434 {
01435
01436 struct ast_vm_user *vmu = NULL, *cur;
01437 AST_LIST_LOCK(&users);
01438
01439 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01440 context = "default";
01441
01442 AST_LIST_TRAVERSE(&users, cur, list) {
01443 #ifdef IMAP_STORAGE
01444 if (cur->imapversion != imapversion) {
01445 continue;
01446 }
01447 #endif
01448 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01449 break;
01450 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01451 break;
01452 }
01453 if (cur) {
01454
01455 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01456 *vmu = *cur;
01457 if (!ivm) {
01458 vmu->emailbody = ast_strdup(cur->emailbody);
01459 vmu->emailsubject = ast_strdup(cur->emailsubject);
01460 }
01461 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01462 AST_LIST_NEXT(vmu, list) = NULL;
01463 }
01464 } else
01465 vmu = find_user_realtime(ivm, context, mailbox);
01466 AST_LIST_UNLOCK(&users);
01467 return vmu;
01468 }
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01481 {
01482
01483 struct ast_vm_user *cur;
01484 int res = -1;
01485 AST_LIST_LOCK(&users);
01486 AST_LIST_TRAVERSE(&users, cur, list) {
01487 if ((!context || !strcasecmp(context, cur->context)) &&
01488 (!strcasecmp(mailbox, cur->mailbox)))
01489 break;
01490 }
01491 if (cur) {
01492 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01493 res = 0;
01494 }
01495 AST_LIST_UNLOCK(&users);
01496 return res;
01497 }
01498
01499
01500
01501
01502
01503
01504
01505
01506 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01507 {
01508 struct ast_config *cfg = NULL;
01509 struct ast_variable *var = NULL;
01510 struct ast_category *cat = NULL;
01511 char *category = NULL, *value = NULL, *new = NULL;
01512 const char *tmp = NULL;
01513 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01514 char secretfn[PATH_MAX] = "";
01515 int found = 0;
01516
01517 if (!change_password_realtime(vmu, newpassword))
01518 return;
01519
01520
01521 switch (vmu->passwordlocation) {
01522 case OPT_PWLOC_SPOOLDIR:
01523 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01524 if (write_password_to_file(secretfn, newpassword) == 0) {
01525 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
01526 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01527 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01528 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01529 break;
01530 } else {
01531 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01532 }
01533
01534 case OPT_PWLOC_VOICEMAILCONF:
01535 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01536 while ((category = ast_category_browse(cfg, category))) {
01537 if (!strcasecmp(category, vmu->context)) {
01538 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01539 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01540 break;
01541 }
01542 value = strstr(tmp, ",");
01543 if (!value) {
01544 new = alloca(strlen(newpassword)+1);
01545 sprintf(new, "%s", newpassword);
01546 } else {
01547 new = alloca((strlen(value) + strlen(newpassword) + 1));
01548 sprintf(new, "%s%s", newpassword, value);
01549 }
01550 if (!(cat = ast_category_get(cfg, category))) {
01551 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01552 break;
01553 }
01554 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01555 found = 1;
01556 }
01557 }
01558
01559 if (found) {
01560 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
01561 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01562 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01563 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01564 break;
01565 }
01566 }
01567
01568 case OPT_PWLOC_USERSCONF:
01569
01570
01571 if ((cfg = ast_config_load("users.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01572 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01573 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01574 ast_debug(4, "users.conf: %s\n", category);
01575 if (!strcasecmp(category, vmu->mailbox)) {
01576 if (!ast_variable_retrieve(cfg, category, "vmsecret")) {
01577 ast_debug(3, "looks like we need to make vmsecret!\n");
01578 var = ast_variable_new("vmsecret", newpassword, "");
01579 } else {
01580 var = NULL;
01581 }
01582 new = alloca(strlen(newpassword) + 1);
01583 sprintf(new, "%s", newpassword);
01584 if (!(cat = ast_category_get(cfg, category))) {
01585 ast_debug(4, "failed to get category!\n");
01586 ast_free(var);
01587 break;
01588 }
01589 if (!var) {
01590 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01591 } else {
01592 ast_variable_append(cat, var);
01593 }
01594 found = 1;
01595 break;
01596 }
01597 }
01598
01599 if (found) {
01600 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
01601 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01602 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01603 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01604 }
01605 }
01606 }
01607 }
01608
01609 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01610 {
01611 char buf[255];
01612 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01613 ast_debug(1, "External password: %s\n",buf);
01614 if (!ast_safe_system(buf)) {
01615 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
01616 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01617
01618 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01619 }
01620 }
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01636 {
01637 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01638 }
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652 static int make_file(char *dest, const int len, const char *dir, const int num)
01653 {
01654 return snprintf(dest, len, "%s/msg%04d", dir, num);
01655 }
01656
01657
01658 static FILE *vm_mkftemp(char *template)
01659 {
01660 FILE *p = NULL;
01661 int pfd = mkstemp(template);
01662 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01663 if (pfd > -1) {
01664 p = fdopen(pfd, "w+");
01665 if (!p) {
01666 close(pfd);
01667 pfd = -1;
01668 }
01669 }
01670 return p;
01671 }
01672
01673
01674
01675
01676
01677
01678
01679
01680
01681 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01682 {
01683 mode_t mode = VOICEMAIL_DIR_MODE;
01684 int res;
01685
01686 make_dir(dest, len, context, ext, folder);
01687 if ((res = ast_mkdir(dest, mode))) {
01688 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01689 return -1;
01690 }
01691 return 0;
01692 }
01693
01694 static const char * const mailbox_folders[] = {
01695 #ifdef IMAP_STORAGE
01696 imapfolder,
01697 #else
01698 "INBOX",
01699 #endif
01700 "Old",
01701 "Work",
01702 "Family",
01703 "Friends",
01704 "Cust1",
01705 "Cust2",
01706 "Cust3",
01707 "Cust4",
01708 "Cust5",
01709 "Deleted",
01710 "Urgent",
01711 };
01712
01713 static const char *mbox(struct ast_vm_user *vmu, int id)
01714 {
01715 #ifdef IMAP_STORAGE
01716 if (vmu && id == 0) {
01717 return vmu->imapfolder;
01718 }
01719 #endif
01720 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01721 }
01722
01723 static int get_folder_by_name(const char *name)
01724 {
01725 size_t i;
01726
01727 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01728 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01729 return i;
01730 }
01731 }
01732
01733 return -1;
01734 }
01735
01736 static void free_user(struct ast_vm_user *vmu)
01737 {
01738 if (ast_test_flag(vmu, VM_ALLOCED)) {
01739
01740 ast_free(vmu->emailbody);
01741 vmu->emailbody = NULL;
01742
01743 ast_free(vmu->emailsubject);
01744 vmu->emailsubject = NULL;
01745
01746 ast_free(vmu);
01747 }
01748 }
01749
01750 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01751
01752 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01753
01754
01755 if (vms->deleted) {
01756 ast_free(vms->deleted);
01757 vms->deleted = NULL;
01758 }
01759 if (vms->heard) {
01760 ast_free(vms->heard);
01761 vms->heard = NULL;
01762 }
01763 vms->dh_arraysize = 0;
01764
01765 if (arraysize > 0) {
01766 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01767 return -1;
01768 }
01769 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01770 ast_free(vms->deleted);
01771 vms->deleted = NULL;
01772 return -1;
01773 }
01774 vms->dh_arraysize = arraysize;
01775 }
01776
01777 return 0;
01778 }
01779
01780
01781
01782 #ifdef IMAP_STORAGE
01783 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01784 {
01785 char arg[10];
01786 struct vm_state *vms;
01787 unsigned long messageNum;
01788
01789
01790 if (msgnum < 0 && !imapgreetings) {
01791 ast_filedelete(file, NULL);
01792 return;
01793 }
01794
01795 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01796 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);
01797 return;
01798 }
01799
01800
01801
01802 messageNum = vms->msgArray[msgnum];
01803 if (messageNum == 0) {
01804 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01805 return;
01806 }
01807 if (option_debug > 2)
01808 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01809
01810 snprintf (arg, sizeof(arg), "%lu", messageNum);
01811 ast_mutex_lock(&vms->lock);
01812 mail_setflag (vms->mailstream, arg, "\\DELETED");
01813 mail_expunge(vms->mailstream);
01814 ast_mutex_unlock(&vms->lock);
01815 }
01816
01817 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01818 {
01819 struct vm_state *vms_p;
01820 char *file, *filename;
01821 char *attachment;
01822 int i;
01823 BODY *body;
01824
01825
01826
01827
01828 if (msgnum > -1 || !imapgreetings) {
01829 return 0;
01830 } else {
01831 file = strrchr(ast_strdupa(dir), '/');
01832 if (file)
01833 *file++ = '\0';
01834 else {
01835 ast_debug (1, "Failed to procure file name from directory passed.\n");
01836 return -1;
01837 }
01838 }
01839
01840
01841 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01842 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01843
01844
01845
01846
01847 if (!(vms_p = create_vm_state_from_user(vmu))) {
01848 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01849 return -1;
01850 }
01851 }
01852
01853
01854 *vms_p->introfn = '\0';
01855
01856 ast_mutex_lock(&vms_p->lock);
01857 init_mailstream(vms_p, GREETINGS_FOLDER);
01858 if (!vms_p->mailstream) {
01859 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01860 ast_mutex_unlock(&vms_p->lock);
01861 return -1;
01862 }
01863
01864
01865 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01866 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01867
01868 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01869 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01870 } else {
01871 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01872 ast_mutex_unlock(&vms_p->lock);
01873 return -1;
01874 }
01875 filename = strsep(&attachment, ".");
01876 if (!strcmp(filename, file)) {
01877 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01878 vms_p->msgArray[vms_p->curmsg] = i + 1;
01879 save_body(body, vms_p, "2", attachment, 0);
01880 ast_mutex_unlock(&vms_p->lock);
01881 return 0;
01882 }
01883 }
01884 ast_mutex_unlock(&vms_p->lock);
01885
01886 return -1;
01887 }
01888
01889 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01890 {
01891 BODY *body;
01892 char *header_content;
01893 char *attachedfilefmt;
01894 char buf[80];
01895 struct vm_state *vms;
01896 char text_file[PATH_MAX];
01897 FILE *text_file_ptr;
01898 int res = 0;
01899 struct ast_vm_user *vmu;
01900
01901 if (!(vmu = find_user(NULL, context, mailbox))) {
01902 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01903 return -1;
01904 }
01905
01906 if (msgnum < 0) {
01907 if (imapgreetings) {
01908 res = imap_retrieve_greeting(dir, msgnum, vmu);
01909 goto exit;
01910 } else {
01911 res = 0;
01912 goto exit;
01913 }
01914 }
01915
01916
01917
01918
01919 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01920
01921
01922
01923
01924
01925
01926
01927 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01928 res = -1;
01929 goto exit;
01930 }
01931
01932 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01933 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01934
01935
01936 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01937 res = 0;
01938 goto exit;
01939 }
01940
01941 if (option_debug > 2)
01942 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01943 if (vms->msgArray[msgnum] == 0) {
01944 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01945 res = -1;
01946 goto exit;
01947 }
01948
01949
01950 ast_mutex_lock(&vms->lock);
01951 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01952 ast_mutex_unlock(&vms->lock);
01953
01954 if (ast_strlen_zero(header_content)) {
01955 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01956 res = -1;
01957 goto exit;
01958 }
01959
01960 ast_mutex_lock(&vms->lock);
01961 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01962 ast_mutex_unlock(&vms->lock);
01963
01964
01965 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01966 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01967 } else {
01968 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01969 res = -1;
01970 goto exit;
01971 }
01972
01973
01974
01975 strsep(&attachedfilefmt, ".");
01976 if (!attachedfilefmt) {
01977 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01978 res = -1;
01979 goto exit;
01980 }
01981
01982 save_body(body, vms, "2", attachedfilefmt, 0);
01983 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
01984 *vms->introfn = '\0';
01985 }
01986
01987
01988 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
01989
01990 if (!(text_file_ptr = fopen(text_file, "w"))) {
01991 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
01992 }
01993
01994 fprintf(text_file_ptr, "%s\n", "[message]");
01995
01996 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
01997 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
01998 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
01999 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
02000 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
02001 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
02002 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
02003 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
02004 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
02005 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
02006 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
02007 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
02008 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
02009 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
02010 fclose(text_file_ptr);
02011
02012 exit:
02013 free_user(vmu);
02014 return res;
02015 }
02016
02017 static int folder_int(const char *folder)
02018 {
02019
02020 if (!folder) {
02021 return 0;
02022 }
02023 if (!strcasecmp(folder, imapfolder)) {
02024 return 0;
02025 } else if (!strcasecmp(folder, "Old")) {
02026 return 1;
02027 } else if (!strcasecmp(folder, "Work")) {
02028 return 2;
02029 } else if (!strcasecmp(folder, "Family")) {
02030 return 3;
02031 } else if (!strcasecmp(folder, "Friends")) {
02032 return 4;
02033 } else if (!strcasecmp(folder, "Cust1")) {
02034 return 5;
02035 } else if (!strcasecmp(folder, "Cust2")) {
02036 return 6;
02037 } else if (!strcasecmp(folder, "Cust3")) {
02038 return 7;
02039 } else if (!strcasecmp(folder, "Cust4")) {
02040 return 8;
02041 } else if (!strcasecmp(folder, "Cust5")) {
02042 return 9;
02043 } else if (!strcasecmp(folder, "Urgent")) {
02044 return 11;
02045 } else {
02046 return 0;
02047 }
02048 }
02049
02050 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02051 {
02052 SEARCHPGM *pgm;
02053 SEARCHHEADER *hdr;
02054
02055 struct ast_vm_user *vmu, vmus;
02056 struct vm_state *vms_p;
02057 int ret = 0;
02058 int fold = folder_int(folder);
02059 int urgent = 0;
02060
02061
02062 if (fold == 11) {
02063 fold = NEW_FOLDER;
02064 urgent = 1;
02065 }
02066
02067 if (ast_strlen_zero(mailbox))
02068 return 0;
02069
02070
02071 vmu = find_user(&vmus, context, mailbox);
02072 if (!vmu) {
02073 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02074 return -1;
02075 } else {
02076
02077 if (vmu->imapuser[0] == '\0') {
02078 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02079 return -1;
02080 }
02081 }
02082
02083
02084 if (vmu->imapuser[0] == '\0') {
02085 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02086 free_user(vmu);
02087 return -1;
02088 }
02089
02090
02091 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02092 if (!vms_p) {
02093 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02094 }
02095 if (vms_p) {
02096 ast_debug(3, "Returning before search - user is logged in\n");
02097 if (fold == 0) {
02098 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02099 }
02100 if (fold == 1) {
02101 return vms_p->oldmessages;
02102 }
02103 }
02104
02105
02106 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02107 if (!vms_p) {
02108 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02109 }
02110
02111 if (!vms_p) {
02112 vms_p = create_vm_state_from_user(vmu);
02113 }
02114 ret = init_mailstream(vms_p, fold);
02115 if (!vms_p->mailstream) {
02116 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02117 return -1;
02118 }
02119 if (ret == 0) {
02120 ast_mutex_lock(&vms_p->lock);
02121 pgm = mail_newsearchpgm ();
02122 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02123 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02124 pgm->header = hdr;
02125 if (fold != OLD_FOLDER) {
02126 pgm->unseen = 1;
02127 pgm->seen = 0;
02128 }
02129
02130
02131
02132 else {
02133 pgm->unseen = 0;
02134 pgm->seen = 1;
02135 }
02136
02137 if (fold == NEW_FOLDER) {
02138 if (urgent) {
02139 pgm->flagged = 1;
02140 pgm->unflagged = 0;
02141 } else {
02142 pgm->flagged = 0;
02143 pgm->unflagged = 1;
02144 }
02145 }
02146 pgm->undeleted = 1;
02147 pgm->deleted = 0;
02148
02149 vms_p->vmArrayIndex = 0;
02150 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02151 if (fold == 0 && urgent == 0)
02152 vms_p->newmessages = vms_p->vmArrayIndex;
02153 if (fold == 1)
02154 vms_p->oldmessages = vms_p->vmArrayIndex;
02155 if (fold == 0 && urgent == 1)
02156 vms_p->urgentmessages = vms_p->vmArrayIndex;
02157
02158 mail_free_searchpgm(&pgm);
02159 ast_mutex_unlock(&vms_p->lock);
02160 vms_p->updated = 0;
02161 return vms_p->vmArrayIndex;
02162 } else {
02163 ast_mutex_lock(&vms_p->lock);
02164 mail_ping(vms_p->mailstream);
02165 ast_mutex_unlock(&vms_p->lock);
02166 }
02167 return 0;
02168 }
02169
02170 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02171 {
02172
02173 check_quota(vms, vmu->imapfolder);
02174 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02175 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02176 ast_play_and_wait(chan, "vm-mailboxfull");
02177 return -1;
02178 }
02179
02180
02181 ast_debug(3, "Checking message number quota: mailbox has %d messages, maximum is set to %d, current messages %d\n", msgnum, vmu->maxmsg, inprocess_count(vmu->mailbox, vmu->context, 0));
02182 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02183 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02184 ast_play_and_wait(chan, "vm-mailboxfull");
02185 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02186 return -1;
02187 }
02188
02189 return 0;
02190 }
02191
02192
02193
02194
02195
02196
02197
02198
02199
02200
02201 static int messagecount(const char *context, const char *mailbox, const char *folder)
02202 {
02203 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02204 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02205 } else {
02206 return __messagecount(context, mailbox, folder);
02207 }
02208 }
02209
02210 static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag)
02211 {
02212 char *myserveremail = serveremail;
02213 char fn[PATH_MAX];
02214 char introfn[PATH_MAX];
02215 char mailbox[256];
02216 char *stringp;
02217 FILE *p = NULL;
02218 char tmp[80] = "/tmp/astmail-XXXXXX";
02219 long len;
02220 void *buf;
02221 int tempcopy = 0;
02222 STRING str;
02223 int ret;
02224 char *imap_flags = NIL;
02225 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02226 int box = NEW_FOLDER;
02227
02228
02229 if (msgnum < 0) {
02230 if(!imapgreetings) {
02231 return 0;
02232 } else {
02233 box = GREETINGS_FOLDER;
02234 }
02235 }
02236
02237 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02238 return -1;
02239 }
02240
02241
02242 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02243 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02244 imap_flags = "\\FLAGGED";
02245 }
02246
02247
02248 fmt = ast_strdupa(fmt);
02249 stringp = fmt;
02250 strsep(&stringp, "|");
02251
02252 if (!ast_strlen_zero(vmu->serveremail))
02253 myserveremail = vmu->serveremail;
02254
02255 if (msgnum > -1)
02256 make_file(fn, sizeof(fn), dir, msgnum);
02257 else
02258 ast_copy_string (fn, dir, sizeof(fn));
02259
02260 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02261 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02262 *introfn = '\0';
02263 }
02264
02265 if (ast_strlen_zero(vmu->email)) {
02266
02267
02268
02269
02270
02271 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02272 tempcopy = 1;
02273 }
02274
02275 if (!strcmp(fmt, "wav49"))
02276 fmt = "WAV";
02277 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02278
02279
02280
02281 if (!(p = vm_mkftemp(tmp))) {
02282 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02283 if (tempcopy)
02284 *(vmu->email) = '\0';
02285 return -1;
02286 }
02287
02288 if (msgnum < 0 && imapgreetings) {
02289 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02290 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02291 return -1;
02292 }
02293 imap_delete_old_greeting(fn, vms);
02294 }
02295
02296 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02297 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02298 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02299 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02300
02301 len = ftell(p);
02302 rewind(p);
02303 if (!(buf = ast_malloc(len + 1))) {
02304 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02305 fclose(p);
02306 if (tempcopy)
02307 *(vmu->email) = '\0';
02308 return -1;
02309 }
02310 if (fread(buf, len, 1, p) < len) {
02311 if (ferror(p)) {
02312 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02313 return -1;
02314 }
02315 }
02316 ((char *) buf)[len] = '\0';
02317 INIT(&str, mail_string, buf, len);
02318 ret = init_mailstream(vms, box);
02319 if (ret == 0) {
02320 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
02321 ast_mutex_lock(&vms->lock);
02322 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02323 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02324 ast_mutex_unlock(&vms->lock);
02325 fclose(p);
02326 unlink(tmp);
02327 ast_free(buf);
02328 } else {
02329 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02330 fclose(p);
02331 unlink(tmp);
02332 ast_free(buf);
02333 return -1;
02334 }
02335 ast_debug(3, "%s stored\n", fn);
02336
02337 if (tempcopy)
02338 *(vmu->email) = '\0';
02339 inprocess_count(vmu->mailbox, vmu->context, -1);
02340 return 0;
02341
02342 }
02343
02344
02345
02346
02347
02348
02349
02350
02351
02352
02353
02354
02355
02356
02357 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02358 {
02359 char tmp[PATH_MAX] = "";
02360 char *mailboxnc;
02361 char *context;
02362 char *mb;
02363 char *cur;
02364 if (newmsgs)
02365 *newmsgs = 0;
02366 if (oldmsgs)
02367 *oldmsgs = 0;
02368 if (urgentmsgs)
02369 *urgentmsgs = 0;
02370
02371 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02372
02373 if (ast_strlen_zero(mailbox_context))
02374 return 0;
02375
02376 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02377 context = strchr(tmp, '@');
02378 if (strchr(mailbox_context, ',')) {
02379 int tmpnew, tmpold, tmpurgent;
02380 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02381 mb = tmp;
02382 while ((cur = strsep(&mb, ", "))) {
02383 if (!ast_strlen_zero(cur)) {
02384 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02385 return -1;
02386 else {
02387 if (newmsgs)
02388 *newmsgs += tmpnew;
02389 if (oldmsgs)
02390 *oldmsgs += tmpold;
02391 if (urgentmsgs)
02392 *urgentmsgs += tmpurgent;
02393 }
02394 }
02395 }
02396 return 0;
02397 }
02398 if (context) {
02399 *context = '\0';
02400 mailboxnc = tmp;
02401 context++;
02402 } else {
02403 context = "default";
02404 mailboxnc = (char *) mailbox_context;
02405 }
02406
02407 if (newmsgs) {
02408 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02409 if (!vmu) {
02410 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02411 return -1;
02412 }
02413 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02414 return -1;
02415 }
02416 }
02417 if (oldmsgs) {
02418 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02419 return -1;
02420 }
02421 }
02422 if (urgentmsgs) {
02423 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02424 return -1;
02425 }
02426 }
02427 return 0;
02428 }
02429
02430
02431
02432
02433
02434
02435
02436
02437
02438
02439
02440 static int has_voicemail(const char *mailbox, const char *folder)
02441 {
02442 char tmp[256], *tmp2, *box, *context;
02443 ast_copy_string(tmp, mailbox, sizeof(tmp));
02444 tmp2 = tmp;
02445 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02446 while ((box = strsep(&tmp2, ",&"))) {
02447 if (!ast_strlen_zero(box)) {
02448 if (has_voicemail(box, folder)) {
02449 return 1;
02450 }
02451 }
02452 }
02453 }
02454 if ((context = strchr(tmp, '@'))) {
02455 *context++ = '\0';
02456 } else {
02457 context = "default";
02458 }
02459 return __messagecount(context, tmp, folder) ? 1 : 0;
02460 }
02461
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472
02473
02474
02475
02476
02477 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)
02478 {
02479 struct vm_state *sendvms = NULL, *destvms = NULL;
02480 char messagestring[10];
02481 if (msgnum >= recip->maxmsg) {
02482 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02483 return -1;
02484 }
02485 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02486 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02487 return -1;
02488 }
02489 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02490 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02491 return -1;
02492 }
02493 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02494 ast_mutex_lock(&sendvms->lock);
02495 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02496 ast_mutex_unlock(&sendvms->lock);
02497 return 0;
02498 }
02499 ast_mutex_unlock(&sendvms->lock);
02500 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02501 return -1;
02502 }
02503
02504 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02505 {
02506 char tmp[256], *t = tmp;
02507 size_t left = sizeof(tmp);
02508
02509 if (box == OLD_FOLDER) {
02510 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02511 } else {
02512 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02513 }
02514
02515 if (box == NEW_FOLDER) {
02516 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02517 } else {
02518 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02519 }
02520
02521
02522 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02523
02524
02525 if (!ast_strlen_zero(authuser))
02526 ast_build_string(&t, &left, "/authuser=%s", authuser);
02527
02528
02529 if (!ast_strlen_zero(imapflags))
02530 ast_build_string(&t, &left, "/%s", imapflags);
02531
02532
02533 #if 1
02534 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02535 #else
02536 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02537 #endif
02538 if (box == NEW_FOLDER || box == OLD_FOLDER)
02539 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02540 else if (box == GREETINGS_FOLDER)
02541 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02542 else {
02543 if (!ast_strlen_zero(imapparentfolder)) {
02544
02545 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02546 } else {
02547 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02548 }
02549 }
02550 }
02551
02552 static int init_mailstream(struct vm_state *vms, int box)
02553 {
02554 MAILSTREAM *stream = NIL;
02555 long debug;
02556 char tmp[256];
02557
02558 if (!vms) {
02559 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02560 return -1;
02561 }
02562 if (option_debug > 2)
02563 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02564 if (vms->mailstream == NIL || !vms->mailstream) {
02565 if (option_debug)
02566 ast_log(LOG_DEBUG, "mailstream not set.\n");
02567 } else {
02568 stream = vms->mailstream;
02569 }
02570
02571 debug = NIL;
02572
02573 if (delimiter == '\0') {
02574 char *cp;
02575 #ifdef USE_SYSTEM_IMAP
02576 #include <imap/linkage.c>
02577 #elif defined(USE_SYSTEM_CCLIENT)
02578 #include <c-client/linkage.c>
02579 #else
02580 #include "linkage.c"
02581 #endif
02582
02583 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02584 ast_mutex_lock(&vms->lock);
02585 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02586 ast_mutex_unlock(&vms->lock);
02587 if (stream == NIL) {
02588 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02589 return -1;
02590 }
02591 get_mailbox_delimiter(stream);
02592
02593 for (cp = vms->imapfolder; *cp; cp++)
02594 if (*cp == '/')
02595 *cp = delimiter;
02596 }
02597
02598 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02599 if (option_debug > 2)
02600 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02601 ast_mutex_lock(&vms->lock);
02602 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02603 ast_mutex_unlock(&vms->lock);
02604 if (vms->mailstream == NIL) {
02605 return -1;
02606 } else {
02607 return 0;
02608 }
02609 }
02610
02611 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02612 {
02613 SEARCHPGM *pgm;
02614 SEARCHHEADER *hdr;
02615 int ret, urgent = 0;
02616
02617
02618 if (box == 11) {
02619 box = NEW_FOLDER;
02620 urgent = 1;
02621 }
02622
02623 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02624 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02625 vms->imapversion = vmu->imapversion;
02626 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02627
02628 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02629 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02630 return -1;
02631 }
02632
02633 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02634
02635
02636 if (box == 0) {
02637 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02638 check_quota(vms, (char *) mbox(vmu, box));
02639 }
02640
02641 ast_mutex_lock(&vms->lock);
02642 pgm = mail_newsearchpgm();
02643
02644
02645 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02646 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02647 pgm->header = hdr;
02648 pgm->deleted = 0;
02649 pgm->undeleted = 1;
02650
02651
02652 if (box == NEW_FOLDER && urgent == 1) {
02653 pgm->unseen = 1;
02654 pgm->seen = 0;
02655 pgm->flagged = 1;
02656 pgm->unflagged = 0;
02657 } else if (box == NEW_FOLDER && urgent == 0) {
02658 pgm->unseen = 1;
02659 pgm->seen = 0;
02660 pgm->flagged = 0;
02661 pgm->unflagged = 1;
02662 } else if (box == OLD_FOLDER) {
02663 pgm->seen = 1;
02664 pgm->unseen = 0;
02665 }
02666
02667 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02668
02669 vms->vmArrayIndex = 0;
02670 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02671 vms->lastmsg = vms->vmArrayIndex - 1;
02672 mail_free_searchpgm(&pgm);
02673
02674
02675
02676
02677 if (box == 0 && !vms->dh_arraysize) {
02678 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02679 }
02680 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02681 ast_mutex_unlock(&vms->lock);
02682 return -1;
02683 }
02684
02685 ast_mutex_unlock(&vms->lock);
02686 return 0;
02687 }
02688
02689 static void write_file(char *filename, char *buffer, unsigned long len)
02690 {
02691 FILE *output;
02692
02693 output = fopen (filename, "w");
02694 if (fwrite(buffer, len, 1, output) != 1) {
02695 if (ferror(output)) {
02696 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02697 }
02698 }
02699 fclose (output);
02700 }
02701
02702 static void update_messages_by_imapuser(const char *user, unsigned long number)
02703 {
02704 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02705
02706 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02707 return;
02708 }
02709
02710 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02711 vms->msgArray[vms->vmArrayIndex++] = number;
02712 }
02713
02714 void mm_searched(MAILSTREAM *stream, unsigned long number)
02715 {
02716 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02717
02718 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02719 return;
02720
02721 update_messages_by_imapuser(user, number);
02722 }
02723
02724 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02725 {
02726 struct ast_variable *var;
02727 struct ast_vm_user *vmu;
02728
02729 vmu = ast_calloc(1, sizeof *vmu);
02730 if (!vmu)
02731 return NULL;
02732 ast_set_flag(vmu, VM_ALLOCED);
02733 populate_defaults(vmu);
02734
02735 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02736 if (var) {
02737 apply_options_full(vmu, var);
02738 ast_variables_destroy(var);
02739 return vmu;
02740 } else {
02741 ast_free(vmu);
02742 return NULL;
02743 }
02744 }
02745
02746
02747
02748 void mm_exists(MAILSTREAM * stream, unsigned long number)
02749 {
02750
02751 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02752 if (number == 0) return;
02753 set_update(stream);
02754 }
02755
02756
02757 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02758 {
02759
02760 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02761 if (number == 0) return;
02762 set_update(stream);
02763 }
02764
02765
02766 void mm_flags(MAILSTREAM * stream, unsigned long number)
02767 {
02768
02769 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02770 if (number == 0) return;
02771 set_update(stream);
02772 }
02773
02774
02775 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02776 {
02777 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02778 mm_log (string, errflg);
02779 }
02780
02781
02782 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02783 {
02784 if (delimiter == '\0') {
02785 delimiter = delim;
02786 }
02787
02788 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02789 if (attributes & LATT_NOINFERIORS)
02790 ast_debug(5, "no inferiors\n");
02791 if (attributes & LATT_NOSELECT)
02792 ast_debug(5, "no select\n");
02793 if (attributes & LATT_MARKED)
02794 ast_debug(5, "marked\n");
02795 if (attributes & LATT_UNMARKED)
02796 ast_debug(5, "unmarked\n");
02797 }
02798
02799
02800 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02801 {
02802 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02803 if (attributes & LATT_NOINFERIORS)
02804 ast_debug(5, "no inferiors\n");
02805 if (attributes & LATT_NOSELECT)
02806 ast_debug(5, "no select\n");
02807 if (attributes & LATT_MARKED)
02808 ast_debug(5, "marked\n");
02809 if (attributes & LATT_UNMARKED)
02810 ast_debug(5, "unmarked\n");
02811 }
02812
02813
02814 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02815 {
02816 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02817 if (status->flags & SA_MESSAGES)
02818 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02819 if (status->flags & SA_RECENT)
02820 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02821 if (status->flags & SA_UNSEEN)
02822 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02823 if (status->flags & SA_UIDVALIDITY)
02824 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02825 if (status->flags & SA_UIDNEXT)
02826 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02827 ast_log(AST_LOG_NOTICE, "\n");
02828 }
02829
02830
02831 void mm_log(char *string, long errflg)
02832 {
02833 switch ((short) errflg) {
02834 case NIL:
02835 ast_debug(1, "IMAP Info: %s\n", string);
02836 break;
02837 case PARSE:
02838 case WARN:
02839 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02840 break;
02841 case ERROR:
02842 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02843 break;
02844 }
02845 }
02846
02847
02848 void mm_dlog(char *string)
02849 {
02850 ast_log(AST_LOG_NOTICE, "%s\n", string);
02851 }
02852
02853
02854 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02855 {
02856 struct ast_vm_user *vmu;
02857
02858 ast_debug(4, "Entering callback mm_login\n");
02859
02860 ast_copy_string(user, mb->user, MAILTMPLEN);
02861
02862
02863 if (!ast_strlen_zero(authpassword)) {
02864 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02865 } else {
02866 AST_LIST_TRAVERSE(&users, vmu, list) {
02867 if (!strcasecmp(mb->user, vmu->imapuser)) {
02868 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02869 break;
02870 }
02871 }
02872 if (!vmu) {
02873 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02874 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02875 free_user(vmu);
02876 }
02877 }
02878 }
02879 }
02880
02881
02882 void mm_critical(MAILSTREAM * stream)
02883 {
02884 }
02885
02886
02887 void mm_nocritical(MAILSTREAM * stream)
02888 {
02889 }
02890
02891
02892 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02893 {
02894 kill (getpid (), SIGSTOP);
02895 return NIL;
02896 }
02897
02898
02899 void mm_fatal(char *string)
02900 {
02901 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02902 }
02903
02904
02905 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02906 {
02907 struct vm_state *vms;
02908 char *mailbox = stream->mailbox, *user;
02909 char buf[1024] = "";
02910 unsigned long usage = 0, limit = 0;
02911
02912 while (pquota) {
02913 usage = pquota->usage;
02914 limit = pquota->limit;
02915 pquota = pquota->next;
02916 }
02917
02918 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)))) {
02919 ast_log(AST_LOG_ERROR, "No state found.\n");
02920 return;
02921 }
02922
02923 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02924
02925 vms->quota_usage = usage;
02926 vms->quota_limit = limit;
02927 }
02928
02929 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02930 {
02931 char *start, *eol_pnt;
02932 int taglen;
02933
02934 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02935 return NULL;
02936
02937 taglen = strlen(tag) + 1;
02938 if (taglen < 1)
02939 return NULL;
02940
02941 if (!(start = strstr(header, tag)))
02942 return NULL;
02943
02944
02945 memset(buf, 0, len);
02946
02947 ast_copy_string(buf, start+taglen, len);
02948 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02949 *eol_pnt = '\0';
02950 return buf;
02951 }
02952
02953 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02954 {
02955 char *start, *quote, *eol_pnt;
02956
02957 if (ast_strlen_zero(mailbox))
02958 return NULL;
02959
02960 if (!(start = strstr(mailbox, "/user=")))
02961 return NULL;
02962
02963 ast_copy_string(buf, start+6, len);
02964
02965 if (!(quote = strchr(buf, '\"'))) {
02966 if (!(eol_pnt = strchr(buf, '/')))
02967 eol_pnt = strchr(buf,'}');
02968 *eol_pnt = '\0';
02969 return buf;
02970 } else {
02971 eol_pnt = strchr(buf+1,'\"');
02972 *eol_pnt = '\0';
02973 return buf+1;
02974 }
02975 }
02976
02977 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02978 {
02979 struct vm_state *vms_p;
02980
02981 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
02982 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
02983 return vms_p;
02984 }
02985 if (option_debug > 4)
02986 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
02987 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
02988 return NULL;
02989 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
02990 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
02991 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
02992 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
02993 vms_p->mailstream = NIL;
02994 vms_p->imapversion = vmu->imapversion;
02995 if (option_debug > 4)
02996 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
02997 vms_p->updated = 1;
02998
02999 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
03000 init_vm_state(vms_p);
03001 vmstate_insert(vms_p);
03002 return vms_p;
03003 }
03004
03005 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
03006 {
03007 struct vmstate *vlist = NULL;
03008
03009 if (interactive) {
03010 struct vm_state *vms;
03011 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03012 vms = pthread_getspecific(ts_vmstate.key);
03013 return vms;
03014 }
03015
03016 AST_LIST_LOCK(&vmstates);
03017 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03018 if (!vlist->vms) {
03019 ast_debug(3, "error: vms is NULL for %s\n", user);
03020 continue;
03021 }
03022 if (vlist->vms->imapversion != imapversion) {
03023 continue;
03024 }
03025 if (!vlist->vms->imapuser) {
03026 ast_debug(3, "error: imapuser is NULL for %s\n", user);
03027 continue;
03028 }
03029
03030 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
03031 AST_LIST_UNLOCK(&vmstates);
03032 return vlist->vms;
03033 }
03034 }
03035 AST_LIST_UNLOCK(&vmstates);
03036
03037 ast_debug(3, "%s not found in vmstates\n", user);
03038
03039 return NULL;
03040 }
03041
03042 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
03043 {
03044
03045 struct vmstate *vlist = NULL;
03046 const char *local_context = S_OR(context, "default");
03047
03048 if (interactive) {
03049 struct vm_state *vms;
03050 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03051 vms = pthread_getspecific(ts_vmstate.key);
03052 return vms;
03053 }
03054
03055 AST_LIST_LOCK(&vmstates);
03056 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03057 if (!vlist->vms) {
03058 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03059 continue;
03060 }
03061 if (vlist->vms->imapversion != imapversion) {
03062 continue;
03063 }
03064 if (!vlist->vms->username || !vlist->vms->context) {
03065 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03066 continue;
03067 }
03068
03069 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);
03070
03071 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03072 ast_debug(3, "Found it!\n");
03073 AST_LIST_UNLOCK(&vmstates);
03074 return vlist->vms;
03075 }
03076 }
03077 AST_LIST_UNLOCK(&vmstates);
03078
03079 ast_debug(3, "%s not found in vmstates\n", mailbox);
03080
03081 return NULL;
03082 }
03083
03084 static void vmstate_insert(struct vm_state *vms)
03085 {
03086 struct vmstate *v;
03087 struct vm_state *altvms;
03088
03089
03090
03091
03092 if (vms->interactive == 1) {
03093 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03094 if (altvms) {
03095 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03096 vms->newmessages = altvms->newmessages;
03097 vms->oldmessages = altvms->oldmessages;
03098 vms->vmArrayIndex = altvms->vmArrayIndex;
03099 vms->lastmsg = altvms->lastmsg;
03100 vms->curmsg = altvms->curmsg;
03101
03102 vms->persist_vms = altvms;
03103
03104 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03105 vms->mailstream = altvms->mailstream;
03106 #else
03107 vms->mailstream = NIL;
03108 #endif
03109 }
03110 return;
03111 }
03112
03113 if (!(v = ast_calloc(1, sizeof(*v))))
03114 return;
03115
03116 v->vms = vms;
03117
03118 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03119
03120 AST_LIST_LOCK(&vmstates);
03121 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03122 AST_LIST_UNLOCK(&vmstates);
03123 }
03124
03125 static void vmstate_delete(struct vm_state *vms)
03126 {
03127 struct vmstate *vc = NULL;
03128 struct vm_state *altvms = NULL;
03129
03130
03131
03132 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03133 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03134 altvms->newmessages = vms->newmessages;
03135 altvms->oldmessages = vms->oldmessages;
03136 altvms->updated = 1;
03137 vms->mailstream = mail_close(vms->mailstream);
03138
03139
03140 return;
03141 }
03142
03143 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03144
03145 AST_LIST_LOCK(&vmstates);
03146 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03147 if (vc->vms == vms) {
03148 AST_LIST_REMOVE_CURRENT(list);
03149 break;
03150 }
03151 }
03152 AST_LIST_TRAVERSE_SAFE_END
03153 AST_LIST_UNLOCK(&vmstates);
03154
03155 if (vc) {
03156 ast_mutex_destroy(&vc->vms->lock);
03157 ast_free(vc);
03158 }
03159 else
03160 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03161 }
03162
03163 static void set_update(MAILSTREAM * stream)
03164 {
03165 struct vm_state *vms;
03166 char *mailbox = stream->mailbox, *user;
03167 char buf[1024] = "";
03168
03169 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03170 if (user && option_debug > 2)
03171 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03172 return;
03173 }
03174
03175 ast_debug(3, "User %s mailbox set for update.\n", user);
03176
03177 vms->updated = 1;
03178 }
03179
03180 static void init_vm_state(struct vm_state *vms)
03181 {
03182 int x;
03183 vms->vmArrayIndex = 0;
03184 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
03185 vms->msgArray[x] = 0;
03186 }
03187 ast_mutex_init(&vms->lock);
03188 }
03189
03190 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03191 {
03192 char *body_content;
03193 char *body_decoded;
03194 char *fn = is_intro ? vms->introfn : vms->fn;
03195 unsigned long len;
03196 unsigned long newlen;
03197 char filename[256];
03198
03199 if (!body || body == NIL)
03200 return -1;
03201
03202 ast_mutex_lock(&vms->lock);
03203 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03204 ast_mutex_unlock(&vms->lock);
03205 if (body_content != NIL) {
03206 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03207
03208 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03209
03210 if (!newlen) {
03211 return -1;
03212 }
03213 write_file(filename, (char *) body_decoded, newlen);
03214 } else {
03215 ast_debug(5, "Body of message is NULL.\n");
03216 return -1;
03217 }
03218 return 0;
03219 }
03220
03221
03222
03223
03224
03225
03226
03227
03228 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03229 char tmp[50];
03230 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03231 mail_list(stream, tmp, "*");
03232 }
03233
03234
03235
03236
03237
03238
03239
03240
03241 static void check_quota(struct vm_state *vms, char *mailbox) {
03242 ast_mutex_lock(&vms->lock);
03243 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03244 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03245 if (vms && vms->mailstream != NULL) {
03246 imap_getquotaroot(vms->mailstream, mailbox);
03247 } else {
03248 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03249 }
03250 ast_mutex_unlock(&vms->lock);
03251 }
03252
03253 #endif
03254
03255
03256
03257
03258
03259 static int vm_lock_path(const char *path)
03260 {
03261 switch (ast_lock_path(path)) {
03262 case AST_LOCK_TIMEOUT:
03263 return -1;
03264 default:
03265 return 0;
03266 }
03267 }
03268
03269
03270 #ifdef ODBC_STORAGE
03271 struct generic_prepare_struct {
03272 char *sql;
03273 int argc;
03274 char **argv;
03275 };
03276
03277 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03278 {
03279 struct generic_prepare_struct *gps = data;
03280 int res, i;
03281 SQLHSTMT stmt;
03282
03283 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03284 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03285 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03286 return NULL;
03287 }
03288 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03289 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03290 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03291 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03292 return NULL;
03293 }
03294 for (i = 0; i < gps->argc; i++)
03295 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03296
03297 return stmt;
03298 }
03299
03300
03301
03302
03303
03304
03305
03306
03307
03308
03309
03310
03311
03312
03313
03314 static int retrieve_file(char *dir, int msgnum)
03315 {
03316 int x = 0;
03317 int res;
03318 int fd = -1;
03319 size_t fdlen = 0;
03320 void *fdm = MAP_FAILED;
03321 SQLSMALLINT colcount = 0;
03322 SQLHSTMT stmt;
03323 char sql[PATH_MAX];
03324 char fmt[80]="";
03325 char *c;
03326 char coltitle[256];
03327 SQLSMALLINT collen;
03328 SQLSMALLINT datatype;
03329 SQLSMALLINT decimaldigits;
03330 SQLSMALLINT nullable;
03331 SQLULEN colsize;
03332 SQLLEN colsize2;
03333 FILE *f = NULL;
03334 char rowdata[80];
03335 char fn[PATH_MAX];
03336 char full_fn[PATH_MAX];
03337 char msgnums[80];
03338 char *argv[] = { dir, msgnums };
03339 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03340
03341 struct odbc_obj *obj;
03342 obj = ast_odbc_request_obj(odbc_database, 0);
03343 if (obj) {
03344 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03345 c = strchr(fmt, '|');
03346 if (c)
03347 *c = '\0';
03348 if (!strcasecmp(fmt, "wav49"))
03349 strcpy(fmt, "WAV");
03350 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03351 if (msgnum > -1)
03352 make_file(fn, sizeof(fn), dir, msgnum);
03353 else
03354 ast_copy_string(fn, dir, sizeof(fn));
03355
03356
03357 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03358
03359 if (!(f = fopen(full_fn, "w+"))) {
03360 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03361 goto yuck;
03362 }
03363
03364 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03365 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03366 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03367 if (!stmt) {
03368 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03369 ast_odbc_release_obj(obj);
03370 goto yuck;
03371 }
03372 res = SQLFetch(stmt);
03373 if (res == SQL_NO_DATA) {
03374 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03375 ast_odbc_release_obj(obj);
03376 goto yuck;
03377 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03378 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03379 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03380 ast_odbc_release_obj(obj);
03381 goto yuck;
03382 }
03383 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03384 if (fd < 0) {
03385 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03386 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03387 ast_odbc_release_obj(obj);
03388 goto yuck;
03389 }
03390 res = SQLNumResultCols(stmt, &colcount);
03391 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03392 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03393 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03394 ast_odbc_release_obj(obj);
03395 goto yuck;
03396 }
03397 if (f)
03398 fprintf(f, "[message]\n");
03399 for (x = 0; x < colcount; x++) {
03400 rowdata[0] = '\0';
03401 colsize = 0;
03402 collen = sizeof(coltitle);
03403 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03404 &datatype, &colsize, &decimaldigits, &nullable);
03405 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03406 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03407 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03408 ast_odbc_release_obj(obj);
03409 goto yuck;
03410 }
03411 if (!strcasecmp(coltitle, "recording")) {
03412 off_t offset;
03413 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03414 fdlen = colsize2;
03415 if (fd > -1) {
03416 char tmp[1]="";
03417 lseek(fd, fdlen - 1, SEEK_SET);
03418 if (write(fd, tmp, 1) != 1) {
03419 close(fd);
03420 fd = -1;
03421 continue;
03422 }
03423
03424 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03425 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03426 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03427 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03428 ast_odbc_release_obj(obj);
03429 goto yuck;
03430 } else {
03431 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03432 munmap(fdm, CHUNKSIZE);
03433 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03434 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03435 unlink(full_fn);
03436 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03437 ast_odbc_release_obj(obj);
03438 goto yuck;
03439 }
03440 }
03441 }
03442 if (truncate(full_fn, fdlen) < 0) {
03443 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03444 }
03445 }
03446 } else {
03447 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03448 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03449 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03450 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03451 ast_odbc_release_obj(obj);
03452 goto yuck;
03453 }
03454 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03455 fprintf(f, "%s=%s\n", coltitle, rowdata);
03456 }
03457 }
03458 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03459 ast_odbc_release_obj(obj);
03460 } else
03461 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03462 yuck:
03463 if (f)
03464 fclose(f);
03465 if (fd > -1)
03466 close(fd);
03467 return x - 1;
03468 }
03469
03470
03471
03472
03473
03474
03475
03476
03477
03478
03479
03480
03481 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03482 {
03483 int x = 0;
03484 int res;
03485 SQLHSTMT stmt;
03486 char sql[PATH_MAX];
03487 char rowdata[20];
03488 char *argv[] = { dir };
03489 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03490
03491 struct odbc_obj *obj;
03492 obj = ast_odbc_request_obj(odbc_database, 0);
03493 if (obj) {
03494 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
03495
03496 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03497 if (!stmt) {
03498 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03499 ast_odbc_release_obj(obj);
03500 goto yuck;
03501 }
03502 res = SQLFetch(stmt);
03503 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03504 if (res == SQL_NO_DATA) {
03505 ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
03506 } else {
03507 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03508 }
03509
03510 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03511 ast_odbc_release_obj(obj);
03512 goto yuck;
03513 }
03514 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03515 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03516 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03517 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03518 ast_odbc_release_obj(obj);
03519 goto yuck;
03520 }
03521 if (sscanf(rowdata, "%30d", &x) != 1)
03522 ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
03523 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03524 ast_odbc_release_obj(obj);
03525 return x;
03526 } else
03527 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03528 yuck:
03529 return x - 1;
03530 }
03531
03532
03533
03534
03535
03536
03537
03538
03539
03540
03541 static int message_exists(char *dir, int msgnum)
03542 {
03543 int x = 0;
03544 int res;
03545 SQLHSTMT stmt;
03546 char sql[PATH_MAX];
03547 char rowdata[20];
03548 char msgnums[20];
03549 char *argv[] = { dir, msgnums };
03550 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03551
03552 struct odbc_obj *obj;
03553 obj = ast_odbc_request_obj(odbc_database, 0);
03554 if (obj) {
03555 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03556 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03557 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03558 if (!stmt) {
03559 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03560 ast_odbc_release_obj(obj);
03561 goto yuck;
03562 }
03563 res = SQLFetch(stmt);
03564 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03565 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03566 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03567 ast_odbc_release_obj(obj);
03568 goto yuck;
03569 }
03570 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03571 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03572 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03573 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03574 ast_odbc_release_obj(obj);
03575 goto yuck;
03576 }
03577 if (sscanf(rowdata, "%30d", &x) != 1)
03578 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03579 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03580 ast_odbc_release_obj(obj);
03581 } else
03582 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03583 yuck:
03584 return x;
03585 }
03586
03587
03588
03589
03590
03591
03592
03593
03594
03595
03596 static int count_messages(struct ast_vm_user *vmu, char *dir)
03597 {
03598 int x = 0;
03599 int res;
03600 SQLHSTMT stmt;
03601 char sql[PATH_MAX];
03602 char rowdata[20];
03603 char *argv[] = { dir };
03604 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03605
03606 struct odbc_obj *obj;
03607 obj = ast_odbc_request_obj(odbc_database, 0);
03608 if (obj) {
03609 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03610 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03611 if (!stmt) {
03612 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03613 ast_odbc_release_obj(obj);
03614 goto yuck;
03615 }
03616 res = SQLFetch(stmt);
03617 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03618 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03619 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03620 ast_odbc_release_obj(obj);
03621 goto yuck;
03622 }
03623 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03624 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03625 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03626 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03627 ast_odbc_release_obj(obj);
03628 goto yuck;
03629 }
03630 if (sscanf(rowdata, "%30d", &x) != 1)
03631 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03632 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03633 ast_odbc_release_obj(obj);
03634 return x;
03635 } else
03636 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03637 yuck:
03638 return x - 1;
03639
03640 }
03641
03642
03643
03644
03645
03646
03647
03648
03649
03650
03651
03652 static void delete_file(const char *sdir, int smsg)
03653 {
03654 SQLHSTMT stmt;
03655 char sql[PATH_MAX];
03656 char msgnums[20];
03657 char *argv[] = { NULL, msgnums };
03658 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03659 struct odbc_obj *obj;
03660
03661 argv[0] = ast_strdupa(sdir);
03662
03663 obj = ast_odbc_request_obj(odbc_database, 0);
03664 if (obj) {
03665 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03666 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03667 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03668 if (!stmt)
03669 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03670 else
03671 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03672 ast_odbc_release_obj(obj);
03673 } else
03674 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03675 return;
03676 }
03677
03678
03679
03680
03681
03682
03683
03684
03685
03686
03687
03688
03689 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03690 {
03691 SQLHSTMT stmt;
03692 char sql[512];
03693 char msgnums[20];
03694 char msgnumd[20];
03695 struct odbc_obj *obj;
03696 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03697 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03698
03699 delete_file(ddir, dmsg);
03700 obj = ast_odbc_request_obj(odbc_database, 0);
03701 if (obj) {
03702 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03703 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03704 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);
03705 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03706 if (!stmt)
03707 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03708 else
03709 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03710 ast_odbc_release_obj(obj);
03711 } else
03712 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03713 return;
03714 }
03715
03716 struct insert_data {
03717 char *sql;
03718 const char *dir;
03719 const char *msgnums;
03720 void *data;
03721 SQLLEN datalen;
03722 SQLLEN indlen;
03723 const char *context;
03724 const char *macrocontext;
03725 const char *callerid;
03726 const char *origtime;
03727 const char *duration;
03728 const char *mailboxuser;
03729 const char *mailboxcontext;
03730 const char *category;
03731 const char *flag;
03732 };
03733
03734 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03735 {
03736 struct insert_data *data = vdata;
03737 int res;
03738 SQLHSTMT stmt;
03739
03740 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03741 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03742 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03743 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03744 return NULL;
03745 }
03746
03747 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03748 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03749 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03750 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03751 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03752 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03753 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03754 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03755 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03756 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03757 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03758 if (!ast_strlen_zero(data->category)) {
03759 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03760 }
03761 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03762 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03763 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03764 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03765 return NULL;
03766 }
03767
03768 return stmt;
03769 }
03770
03771
03772
03773
03774
03775
03776
03777
03778
03779
03780
03781
03782
03783
03784 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03785 {
03786 int res = 0;
03787 int fd = -1;
03788 void *fdm = MAP_FAILED;
03789 off_t fdlen = -1;
03790 SQLHSTMT stmt;
03791 char sql[PATH_MAX];
03792 char msgnums[20];
03793 char fn[PATH_MAX];
03794 char full_fn[PATH_MAX];
03795 char fmt[80]="";
03796 char *c;
03797 struct ast_config *cfg = NULL;
03798 struct odbc_obj *obj;
03799 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03800 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03801 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03802
03803 delete_file(dir, msgnum);
03804 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03805 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03806 return -1;
03807 }
03808
03809 do {
03810 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03811 c = strchr(fmt, '|');
03812 if (c)
03813 *c = '\0';
03814 if (!strcasecmp(fmt, "wav49"))
03815 strcpy(fmt, "WAV");
03816 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03817 if (msgnum > -1)
03818 make_file(fn, sizeof(fn), dir, msgnum);
03819 else
03820 ast_copy_string(fn, dir, sizeof(fn));
03821 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03822 cfg = ast_config_load(full_fn, config_flags);
03823 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03824 fd = open(full_fn, O_RDWR);
03825 if (fd < 0) {
03826 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03827 res = -1;
03828 break;
03829 }
03830 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
03831 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03832 idata.context = "";
03833 }
03834 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03835 idata.macrocontext = "";
03836 }
03837 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03838 idata.callerid = "";
03839 }
03840 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03841 idata.origtime = "";
03842 }
03843 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03844 idata.duration = "";
03845 }
03846 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03847 idata.category = "";
03848 }
03849 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03850 idata.flag = "";
03851 }
03852 }
03853 fdlen = lseek(fd, 0, SEEK_END);
03854 if (fdlen < 0 || lseek(fd, 0, SEEK_SET) < 0) {
03855 ast_log(AST_LOG_WARNING, "Failed to process sound file '%s': %s\n", full_fn, strerror(errno));
03856 res = -1;
03857 break;
03858 }
03859 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03860 if (fdm == MAP_FAILED) {
03861 ast_log(AST_LOG_WARNING, "Memory map failed for sound file '%s'!\n", full_fn);
03862 res = -1;
03863 break;
03864 }
03865 idata.data = fdm;
03866 idata.datalen = idata.indlen = fdlen;
03867
03868 if (!ast_strlen_zero(idata.category))
03869 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03870 else
03871 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03872
03873 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03874 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03875 } else {
03876 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03877 res = -1;
03878 }
03879 } while (0);
03880 if (obj) {
03881 ast_odbc_release_obj(obj);
03882 }
03883 if (cfg)
03884 ast_config_destroy(cfg);
03885 if (fdm != MAP_FAILED)
03886 munmap(fdm, fdlen);
03887 if (fd > -1)
03888 close(fd);
03889 return res;
03890 }
03891
03892
03893
03894
03895
03896
03897
03898
03899
03900
03901
03902
03903
03904
03905 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03906 {
03907 SQLHSTMT stmt;
03908 char sql[PATH_MAX];
03909 char msgnums[20];
03910 char msgnumd[20];
03911 struct odbc_obj *obj;
03912 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03913 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03914
03915 delete_file(ddir, dmsg);
03916 obj = ast_odbc_request_obj(odbc_database, 0);
03917 if (obj) {
03918 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03919 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03920 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03921 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03922 if (!stmt)
03923 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03924 else
03925 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03926 ast_odbc_release_obj(obj);
03927 } else
03928 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03929 return;
03930 }
03931
03932
03933
03934
03935
03936
03937
03938
03939
03940
03941
03942
03943 static int remove_file(char *dir, int msgnum)
03944 {
03945 char fn[PATH_MAX];
03946 char full_fn[PATH_MAX];
03947 char msgnums[80];
03948
03949 if (msgnum > -1) {
03950 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03951 make_file(fn, sizeof(fn), dir, msgnum);
03952 } else
03953 ast_copy_string(fn, dir, sizeof(fn));
03954 ast_filedelete(fn, NULL);
03955 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03956 unlink(full_fn);
03957 return 0;
03958 }
03959 #else
03960 #ifndef IMAP_STORAGE
03961
03962
03963
03964
03965
03966
03967
03968
03969
03970 static int count_messages(struct ast_vm_user *vmu, char *dir)
03971 {
03972
03973 int vmcount = 0;
03974 DIR *vmdir = NULL;
03975 struct dirent *vment = NULL;
03976
03977 if (vm_lock_path(dir))
03978 return ERROR_LOCK_PATH;
03979
03980 if ((vmdir = opendir(dir))) {
03981 while ((vment = readdir(vmdir))) {
03982 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
03983 vmcount++;
03984 }
03985 }
03986 closedir(vmdir);
03987 }
03988 ast_unlock_path(dir);
03989
03990 return vmcount;
03991 }
03992
03993
03994
03995
03996
03997
03998
03999
04000 static void rename_file(char *sfn, char *dfn)
04001 {
04002 char stxt[PATH_MAX];
04003 char dtxt[PATH_MAX];
04004 ast_filerename(sfn, dfn, NULL);
04005 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
04006 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
04007 if (ast_check_realtime("voicemail_data")) {
04008 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
04009 }
04010 rename(stxt, dtxt);
04011 }
04012
04013
04014
04015
04016
04017
04018
04019
04020
04021
04022
04023
04024 static int last_message_index(struct ast_vm_user *vmu, char *dir)
04025 {
04026 int x;
04027 unsigned char map[MAXMSGLIMIT] = "";
04028 DIR *msgdir;
04029 struct dirent *msgdirent;
04030 int msgdirint;
04031 char extension[4];
04032 int stopcount = 0;
04033
04034
04035
04036
04037
04038 if (!(msgdir = opendir(dir))) {
04039 return -1;
04040 }
04041
04042 while ((msgdirent = readdir(msgdir))) {
04043 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
04044 map[msgdirint] = 1;
04045 stopcount++;
04046 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
04047 }
04048 }
04049 closedir(msgdir);
04050
04051 for (x = 0; x < vmu->maxmsg; x++) {
04052 if (map[x] == 1) {
04053 stopcount--;
04054 } else if (map[x] == 0 && !stopcount) {
04055 break;
04056 }
04057 }
04058
04059 return x - 1;
04060 }
04061
04062 #endif
04063 #endif
04064 #ifndef IMAP_STORAGE
04065
04066
04067
04068
04069
04070
04071
04072
04073
04074
04075 static int copy(char *infile, char *outfile)
04076 {
04077 int ifd;
04078 int ofd;
04079 int res;
04080 int len;
04081 char buf[4096];
04082
04083 #ifdef HARDLINK_WHEN_POSSIBLE
04084
04085 if (link(infile, outfile)) {
04086 #endif
04087 if ((ifd = open(infile, O_RDONLY)) < 0) {
04088 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
04089 return -1;
04090 }
04091 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
04092 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
04093 close(ifd);
04094 return -1;
04095 }
04096 do {
04097 len = read(ifd, buf, sizeof(buf));
04098 if (len < 0) {
04099 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
04100 close(ifd);
04101 close(ofd);
04102 unlink(outfile);
04103 } else if (len) {
04104 res = write(ofd, buf, len);
04105 if (errno == ENOMEM || errno == ENOSPC || res != len) {
04106 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
04107 close(ifd);
04108 close(ofd);
04109 unlink(outfile);
04110 }
04111 }
04112 } while (len);
04113 close(ifd);
04114 close(ofd);
04115 return 0;
04116 #ifdef HARDLINK_WHEN_POSSIBLE
04117 } else {
04118
04119 return 0;
04120 }
04121 #endif
04122 }
04123
04124
04125
04126
04127
04128
04129
04130
04131
04132
04133 static void copy_plain_file(char *frompath, char *topath)
04134 {
04135 char frompath2[PATH_MAX], topath2[PATH_MAX];
04136 struct ast_variable *tmp,*var = NULL;
04137 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04138 ast_filecopy(frompath, topath, NULL);
04139 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04140 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04141 if (ast_check_realtime("voicemail_data")) {
04142 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04143
04144 for (tmp = var; tmp; tmp = tmp->next) {
04145 if (!strcasecmp(tmp->name, "origmailbox")) {
04146 origmailbox = tmp->value;
04147 } else if (!strcasecmp(tmp->name, "context")) {
04148 context = tmp->value;
04149 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04150 macrocontext = tmp->value;
04151 } else if (!strcasecmp(tmp->name, "exten")) {
04152 exten = tmp->value;
04153 } else if (!strcasecmp(tmp->name, "priority")) {
04154 priority = tmp->value;
04155 } else if (!strcasecmp(tmp->name, "callerchan")) {
04156 callerchan = tmp->value;
04157 } else if (!strcasecmp(tmp->name, "callerid")) {
04158 callerid = tmp->value;
04159 } else if (!strcasecmp(tmp->name, "origdate")) {
04160 origdate = tmp->value;
04161 } else if (!strcasecmp(tmp->name, "origtime")) {
04162 origtime = tmp->value;
04163 } else if (!strcasecmp(tmp->name, "category")) {
04164 category = tmp->value;
04165 } else if (!strcasecmp(tmp->name, "duration")) {
04166 duration = tmp->value;
04167 }
04168 }
04169 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);
04170 }
04171 copy(frompath2, topath2);
04172 ast_variables_destroy(var);
04173 }
04174 #endif
04175
04176
04177
04178
04179
04180
04181
04182
04183
04184 static int vm_delete(char *file)
04185 {
04186 char *txt;
04187 int txtsize = 0;
04188
04189 txtsize = (strlen(file) + 5)*sizeof(char);
04190 txt = alloca(txtsize);
04191
04192
04193
04194 if (ast_check_realtime("voicemail_data")) {
04195 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04196 }
04197 snprintf(txt, txtsize, "%s.txt", file);
04198 unlink(txt);
04199 return ast_filedelete(file, NULL);
04200 }
04201
04202
04203
04204
04205 static int inbuf(struct baseio *bio, FILE *fi)
04206 {
04207 int l;
04208
04209 if (bio->ateof)
04210 return 0;
04211
04212 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04213 if (ferror(fi))
04214 return -1;
04215
04216 bio->ateof = 1;
04217 return 0;
04218 }
04219
04220 bio->iolen = l;
04221 bio->iocp = 0;
04222
04223 return 1;
04224 }
04225
04226
04227
04228
04229 static int inchar(struct baseio *bio, FILE *fi)
04230 {
04231 if (bio->iocp>=bio->iolen) {
04232 if (!inbuf(bio, fi))
04233 return EOF;
04234 }
04235
04236 return bio->iobuf[bio->iocp++];
04237 }
04238
04239
04240
04241
04242 static int ochar(struct baseio *bio, int c, FILE *so)
04243 {
04244 if (bio->linelength >= BASELINELEN) {
04245 if (fputs(ENDL, so) == EOF) {
04246 return -1;
04247 }
04248
04249 bio->linelength = 0;
04250 }
04251
04252 if (putc(((unsigned char) c), so) == EOF) {
04253 return -1;
04254 }
04255
04256 bio->linelength++;
04257
04258 return 1;
04259 }
04260
04261
04262
04263
04264
04265
04266
04267
04268
04269
04270 static int base_encode(char *filename, FILE *so)
04271 {
04272 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04273 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04274 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04275 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04276 int i, hiteof = 0;
04277 FILE *fi;
04278 struct baseio bio;
04279
04280 memset(&bio, 0, sizeof(bio));
04281 bio.iocp = BASEMAXINLINE;
04282
04283 if (!(fi = fopen(filename, "rb"))) {
04284 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04285 return -1;
04286 }
04287
04288 while (!hiteof){
04289 unsigned char igroup[3], ogroup[4];
04290 int c, n;
04291
04292 memset(igroup, 0, sizeof(igroup));
04293
04294 for (n = 0; n < 3; n++) {
04295 if ((c = inchar(&bio, fi)) == EOF) {
04296 hiteof = 1;
04297 break;
04298 }
04299
04300 igroup[n] = (unsigned char) c;
04301 }
04302
04303 if (n > 0) {
04304 ogroup[0]= dtable[igroup[0] >> 2];
04305 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04306 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04307 ogroup[3]= dtable[igroup[2] & 0x3F];
04308
04309 if (n < 3) {
04310 ogroup[3] = '=';
04311
04312 if (n < 2)
04313 ogroup[2] = '=';
04314 }
04315
04316 for (i = 0; i < 4; i++)
04317 ochar(&bio, ogroup[i], so);
04318 }
04319 }
04320
04321 fclose(fi);
04322
04323 if (fputs(ENDL, so) == EOF) {
04324 return 0;
04325 }
04326
04327 return 1;
04328 }
04329
04330 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, const char *category, const char *flag)
04331 {
04332 char callerid[256];
04333 char num[12];
04334 char fromdir[256], fromfile[256];
04335 struct ast_config *msg_cfg;
04336 const char *origcallerid, *origtime;
04337 char origcidname[80], origcidnum[80], origdate[80];
04338 int inttime;
04339 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04340
04341
04342 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04343 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04344 snprintf(num, sizeof(num), "%d", msgnum);
04345 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04346 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04347 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04348 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04349 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04350 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04351 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04352 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04353 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04354 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04355
04356
04357 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04358 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04359 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04360 strcat(fromfile, ".txt");
04361 }
04362 if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
04363 if (option_debug > 0) {
04364 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04365 }
04366 return;
04367 }
04368
04369 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04370 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04371 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04372 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04373 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04374 }
04375
04376 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04377 struct timeval tv = { inttime, };
04378 struct ast_tm tm;
04379 ast_localtime(&tv, &tm, NULL);
04380 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04381 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04382 }
04383 ast_config_destroy(msg_cfg);
04384 }
04385
04386
04387
04388
04389
04390
04391
04392
04393
04394 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04395 {
04396 const char *ptr;
04397
04398
04399 ast_str_set(buf, maxlen, "\"");
04400 for (ptr = from; *ptr; ptr++) {
04401 if (*ptr == '"' || *ptr == '\\') {
04402 ast_str_append(buf, maxlen, "\\%c", *ptr);
04403 } else {
04404 ast_str_append(buf, maxlen, "%c", *ptr);
04405 }
04406 }
04407 ast_str_append(buf, maxlen, "\"");
04408
04409 return ast_str_buffer(*buf);
04410 }
04411
04412
04413
04414
04415
04416 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04417 {
04418 const struct vm_zone *z = NULL;
04419 struct timeval t = ast_tvnow();
04420
04421
04422 if (!ast_strlen_zero(vmu->zonetag)) {
04423
04424 AST_LIST_LOCK(&zones);
04425 AST_LIST_TRAVERSE(&zones, z, list) {
04426 if (!strcmp(z->name, vmu->zonetag))
04427 break;
04428 }
04429 AST_LIST_UNLOCK(&zones);
04430 }
04431 ast_localtime(&t, tm, z ? z->timezone : NULL);
04432 return tm;
04433 }
04434
04435
04436
04437
04438
04439 static int check_mime(const char *str)
04440 {
04441 for (; *str; str++) {
04442 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04443 return 1;
04444 }
04445 }
04446 return 0;
04447 }
04448
04449
04450
04451
04452
04453
04454
04455
04456
04457
04458
04459
04460
04461
04462
04463
04464
04465
04466 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04467 {
04468 struct ast_str *tmp = ast_str_alloca(80);
04469 int first_section = 1;
04470
04471 ast_str_reset(*end);
04472 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04473 for (; *start; start++) {
04474 int need_encoding = 0;
04475 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04476 need_encoding = 1;
04477 }
04478 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04479 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04480 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04481 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04482
04483 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04484 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04485 first_section = 0;
04486 }
04487 if (need_encoding && *start == ' ') {
04488 ast_str_append(&tmp, -1, "_");
04489 } else if (need_encoding) {
04490 ast_str_append(&tmp, -1, "=%hhX", *start);
04491 } else {
04492 ast_str_append(&tmp, -1, "%c", *start);
04493 }
04494 }
04495 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04496 return ast_str_buffer(*end);
04497 }
04498
04499
04500
04501
04502
04503
04504
04505
04506
04507
04508
04509
04510
04511
04512
04513
04514
04515
04516
04517
04518
04519
04520
04521
04522 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)
04523 {
04524 char date[256];
04525 char host[MAXHOSTNAMELEN] = "";
04526 char who[256];
04527 char bound[256];
04528 char dur[256];
04529 struct ast_tm tm;
04530 char enc_cidnum[256] = "", enc_cidname[256] = "";
04531 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04532 char *greeting_attachment;
04533 char filename[256];
04534
04535 if (!str1 || !str2) {
04536 ast_free(str1);
04537 ast_free(str2);
04538 return;
04539 }
04540
04541 if (cidnum) {
04542 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04543 }
04544 if (cidname) {
04545 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04546 }
04547 gethostname(host, sizeof(host) - 1);
04548
04549 if (strchr(srcemail, '@')) {
04550 ast_copy_string(who, srcemail, sizeof(who));
04551 } else {
04552 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04553 }
04554
04555 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04556 if (greeting_attachment) {
04557 *greeting_attachment++ = '\0';
04558 }
04559
04560 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04561 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04562 fprintf(p, "Date: %s" ENDL, date);
04563
04564
04565 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04566
04567 if (!ast_strlen_zero(fromstring)) {
04568 struct ast_channel *ast;
04569 if ((ast = ast_dummy_channel_alloc())) {
04570 char *ptr;
04571 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04572 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04573
04574 if (check_mime(ast_str_buffer(str1))) {
04575 int first_line = 1;
04576 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04577 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04578 *ptr = '\0';
04579 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04580 first_line = 0;
04581
04582 ast_str_set(&str2, 0, "%s", ptr + 1);
04583 }
04584 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04585 } else {
04586 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04587 }
04588 ast = ast_channel_unref(ast);
04589 } else {
04590 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04591 }
04592 } else {
04593 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04594 }
04595
04596 if (check_mime(vmu->fullname)) {
04597 int first_line = 1;
04598 char *ptr;
04599 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04600 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04601 *ptr = '\0';
04602 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04603 first_line = 0;
04604
04605 ast_str_set(&str2, 0, "%s", ptr + 1);
04606 }
04607 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04608 } else {
04609 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04610 }
04611
04612 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04613 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04614 struct ast_channel *ast;
04615 if ((ast = ast_dummy_channel_alloc())) {
04616 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04617 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04618 if (check_mime(ast_str_buffer(str1))) {
04619 int first_line = 1;
04620 char *ptr;
04621 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04622 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04623 *ptr = '\0';
04624 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04625 first_line = 0;
04626
04627 ast_str_set(&str2, 0, "%s", ptr + 1);
04628 }
04629 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04630 } else {
04631 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04632 }
04633 ast = ast_channel_unref(ast);
04634 } else {
04635 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04636 }
04637 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04638 if (ast_strlen_zero(flag)) {
04639 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04640 } else {
04641 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04642 }
04643 } else {
04644 if (ast_strlen_zero(flag)) {
04645 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04646 } else {
04647 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04648 }
04649 }
04650
04651 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1,
04652 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04653 if (imap) {
04654
04655 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04656
04657 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04658 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04659 #ifdef IMAP_STORAGE
04660 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04661 #else
04662 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04663 #endif
04664
04665 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04666 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04667 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04668 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04669 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04670 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04671 if (!ast_strlen_zero(category)) {
04672 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04673 } else {
04674 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04675 }
04676 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04677 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04678 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04679 }
04680 if (!ast_strlen_zero(cidnum)) {
04681 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04682 }
04683 if (!ast_strlen_zero(cidname)) {
04684 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04685 }
04686 fprintf(p, "MIME-Version: 1.0" ENDL);
04687 if (attach_user_voicemail) {
04688
04689 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox,
04690 (int) getpid(), (unsigned int) ast_random());
04691
04692 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04693 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04694 fprintf(p, "--%s" ENDL, bound);
04695 }
04696 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04697 if (emailbody || vmu->emailbody) {
04698 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04699 struct ast_channel *ast;
04700 if ((ast = ast_dummy_channel_alloc())) {
04701 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04702 ast_str_substitute_variables(&str1, 0, ast, e_body);
04703 #ifdef IMAP_STORAGE
04704 {
04705
04706 char *line = ast_str_buffer(str1), *next;
04707 do {
04708
04709 if ((next = strchr(line, '\n'))) {
04710 *next++ = '\0';
04711 }
04712 fprintf(p, "%s" ENDL, line);
04713 line = next;
04714 } while (!ast_strlen_zero(line));
04715 }
04716 #else
04717 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04718 #endif
04719 ast = ast_channel_unref(ast);
04720 } else {
04721 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04722 }
04723 } else if (msgnum > -1) {
04724 if (strcmp(vmu->mailbox, mailbox)) {
04725
04726 struct ast_config *msg_cfg;
04727 const char *v;
04728 int inttime;
04729 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04730 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04731
04732 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04733 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04734 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04735 strcat(fromfile, ".txt");
04736 }
04737 if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
04738 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04739 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04740 }
04741
04742
04743
04744 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04745 struct timeval tv = { inttime, };
04746 struct ast_tm tm;
04747 ast_localtime(&tv, &tm, NULL);
04748 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04749 }
04750 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04751 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04752 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04753 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04754 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04755 date, origcallerid, origdate);
04756 ast_config_destroy(msg_cfg);
04757 } else {
04758 goto plain_message;
04759 }
04760 } else {
04761 plain_message:
04762 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04763 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04764 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04765 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04766 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04767 }
04768 } else {
04769 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04770 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04771 }
04772
04773 if (imap || attach_user_voicemail) {
04774 if (!ast_strlen_zero(attach2)) {
04775 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04776 ast_debug(5, "creating second attachment filename %s\n", filename);
04777 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04778 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04779 ast_debug(5, "creating attachment filename %s\n", filename);
04780 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04781 } else {
04782 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04783 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04784 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04785 }
04786 }
04787 ast_free(str1);
04788 ast_free(str2);
04789 }
04790
04791 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)
04792 {
04793 char tmpdir[256], newtmp[256];
04794 char fname[256];
04795 char tmpcmd[256];
04796 int tmpfd = -1;
04797 int soxstatus = 0;
04798
04799
04800 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04801
04802 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04803 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04804 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04805 tmpfd = mkstemp(newtmp);
04806 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04807 ast_debug(3, "newtmp: %s\n", newtmp);
04808 if (tmpfd > -1) {
04809 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04810 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04811 attach = newtmp;
04812 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04813 } else {
04814 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04815 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04816 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04817 }
04818 }
04819 }
04820 fprintf(p, "--%s" ENDL, bound);
04821 if (msgnum > -1)
04822 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04823 else
04824 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04825 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04826 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04827 if (msgnum > -1)
04828 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04829 else
04830 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04831 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04832 base_encode(fname, p);
04833 if (last)
04834 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04835 if (tmpfd > -1) {
04836 if (soxstatus == 0) {
04837 unlink(fname);
04838 }
04839 close(tmpfd);
04840 unlink(newtmp);
04841 }
04842 return 0;
04843 }
04844
04845 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)
04846 {
04847 FILE *p = NULL;
04848 char tmp[80] = "/tmp/astmail-XXXXXX";
04849 char tmp2[256];
04850 char *stringp;
04851
04852 if (vmu && ast_strlen_zero(vmu->email)) {
04853 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04854 return(0);
04855 }
04856
04857
04858 format = ast_strdupa(format);
04859 stringp = format;
04860 strsep(&stringp, "|");
04861
04862 if (!strcmp(format, "wav49"))
04863 format = "WAV";
04864 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));
04865
04866
04867 if ((p = vm_mkftemp(tmp)) == NULL) {
04868 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04869 return -1;
04870 } else {
04871 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04872 fclose(p);
04873 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04874 ast_safe_system(tmp2);
04875 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04876 }
04877 return 0;
04878 }
04879
04880 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)
04881 {
04882 char enc_cidnum[256], enc_cidname[256];
04883 char date[256];
04884 char host[MAXHOSTNAMELEN] = "";
04885 char who[256];
04886 char dur[PATH_MAX];
04887 char tmp[80] = "/tmp/astmail-XXXXXX";
04888 char tmp2[PATH_MAX];
04889 struct ast_tm tm;
04890 FILE *p;
04891 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04892
04893 if (!str1 || !str2) {
04894 ast_free(str1);
04895 ast_free(str2);
04896 return -1;
04897 }
04898
04899 if (cidnum) {
04900 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04901 }
04902 if (cidname) {
04903 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04904 }
04905
04906 if ((p = vm_mkftemp(tmp)) == NULL) {
04907 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04908 ast_free(str1);
04909 ast_free(str2);
04910 return -1;
04911 }
04912 gethostname(host, sizeof(host)-1);
04913 if (strchr(srcemail, '@')) {
04914 ast_copy_string(who, srcemail, sizeof(who));
04915 } else {
04916 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04917 }
04918 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04919 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04920 fprintf(p, "Date: %s\n", date);
04921
04922
04923 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04924
04925 if (!ast_strlen_zero(pagerfromstring)) {
04926 struct ast_channel *ast;
04927 if ((ast = ast_dummy_channel_alloc())) {
04928 char *ptr;
04929 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04930 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04931
04932 if (check_mime(ast_str_buffer(str1))) {
04933 int first_line = 1;
04934 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04935 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04936 *ptr = '\0';
04937 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04938 first_line = 0;
04939
04940 ast_str_set(&str2, 0, "%s", ptr + 1);
04941 }
04942 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04943 } else {
04944 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04945 }
04946 ast = ast_channel_unref(ast);
04947 } else {
04948 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04949 }
04950 } else {
04951 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04952 }
04953
04954 if (check_mime(vmu->fullname)) {
04955 int first_line = 1;
04956 char *ptr;
04957 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
04958 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04959 *ptr = '\0';
04960 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04961 first_line = 0;
04962
04963 ast_str_set(&str2, 0, "%s", ptr + 1);
04964 }
04965 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
04966 } else {
04967 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
04968 }
04969
04970 if (!ast_strlen_zero(pagersubject)) {
04971 struct ast_channel *ast;
04972 if ((ast = ast_dummy_channel_alloc())) {
04973 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04974 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
04975 if (check_mime(ast_str_buffer(str1))) {
04976 int first_line = 1;
04977 char *ptr;
04978 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04979 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04980 *ptr = '\0';
04981 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04982 first_line = 0;
04983
04984 ast_str_set(&str2, 0, "%s", ptr + 1);
04985 }
04986 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04987 } else {
04988 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04989 }
04990 ast = ast_channel_unref(ast);
04991 } else {
04992 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04993 }
04994 } else {
04995 if (ast_strlen_zero(flag)) {
04996 fprintf(p, "Subject: New VM\n\n");
04997 } else {
04998 fprintf(p, "Subject: New %s VM\n\n", flag);
04999 }
05000 }
05001
05002 if (pagerbody) {
05003 struct ast_channel *ast;
05004 if ((ast = ast_dummy_channel_alloc())) {
05005 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05006 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
05007 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
05008 ast = ast_channel_unref(ast);
05009 } else {
05010 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05011 }
05012 } else {
05013 fprintf(p, "New %s long %s msg in box %s\n"
05014 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
05015 }
05016
05017 fclose(p);
05018 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
05019 ast_safe_system(tmp2);
05020 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
05021 ast_free(str1);
05022 ast_free(str2);
05023 return 0;
05024 }
05025
05026
05027
05028
05029
05030
05031
05032
05033
05034
05035 static int get_date(char *s, int len)
05036 {
05037 struct ast_tm tm;
05038 struct timeval t = ast_tvnow();
05039
05040 ast_localtime(&t, &tm, "UTC");
05041
05042 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
05043 }
05044
05045 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
05046 {
05047 int res;
05048 char fn[PATH_MAX];
05049 char dest[PATH_MAX];
05050
05051 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
05052
05053 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
05054 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
05055 return -1;
05056 }
05057
05058 RETRIEVE(fn, -1, ext, context);
05059 if (ast_fileexists(fn, NULL, NULL) > 0) {
05060 res = ast_stream_and_wait(chan, fn, ecodes);
05061 if (res) {
05062 DISPOSE(fn, -1);
05063 return res;
05064 }
05065 } else {
05066
05067 DISPOSE(fn, -1);
05068 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
05069 if (res)
05070 return res;
05071 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
05072 if (res)
05073 return res;
05074 }
05075 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
05076 return res;
05077 }
05078
05079 static void free_zone(struct vm_zone *z)
05080 {
05081 ast_free(z);
05082 }
05083
05084 #ifdef ODBC_STORAGE
05085 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05086 {
05087 int x = -1;
05088 int res;
05089 SQLHSTMT stmt = NULL;
05090 char sql[PATH_MAX];
05091 char rowdata[20];
05092 char tmp[PATH_MAX] = "";
05093 struct odbc_obj *obj = NULL;
05094 char *context;
05095 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05096
05097 if (newmsgs)
05098 *newmsgs = 0;
05099 if (oldmsgs)
05100 *oldmsgs = 0;
05101 if (urgentmsgs)
05102 *urgentmsgs = 0;
05103
05104
05105 if (ast_strlen_zero(mailbox))
05106 return 0;
05107
05108 ast_copy_string(tmp, mailbox, sizeof(tmp));
05109
05110 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
05111 int u, n, o;
05112 char *next, *remaining = tmp;
05113 while ((next = strsep(&remaining, " ,"))) {
05114 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05115 return -1;
05116 }
05117 if (urgentmsgs) {
05118 *urgentmsgs += u;
05119 }
05120 if (newmsgs) {
05121 *newmsgs += n;
05122 }
05123 if (oldmsgs) {
05124 *oldmsgs += o;
05125 }
05126 }
05127 return 0;
05128 }
05129
05130 context = strchr(tmp, '@');
05131 if (context) {
05132 *context = '\0';
05133 context++;
05134 } else
05135 context = "default";
05136
05137 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05138 do {
05139 if (newmsgs) {
05140 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05141 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05142 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05143 break;
05144 }
05145 res = SQLFetch(stmt);
05146 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05147 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05148 break;
05149 }
05150 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05151 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05152 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05153 break;
05154 }
05155 *newmsgs = atoi(rowdata);
05156 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05157 }
05158
05159 if (oldmsgs) {
05160 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05161 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05162 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05163 break;
05164 }
05165 res = SQLFetch(stmt);
05166 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05167 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05168 break;
05169 }
05170 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05171 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05172 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05173 break;
05174 }
05175 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05176 *oldmsgs = atoi(rowdata);
05177 }
05178
05179 if (urgentmsgs) {
05180 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05181 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05182 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05183 break;
05184 }
05185 res = SQLFetch(stmt);
05186 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05187 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05188 break;
05189 }
05190 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05191 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05192 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05193 break;
05194 }
05195 *urgentmsgs = atoi(rowdata);
05196 }
05197
05198 x = 0;
05199 } while (0);
05200 } else {
05201 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05202 }
05203
05204 if (stmt) {
05205 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05206 }
05207 if (obj) {
05208 ast_odbc_release_obj(obj);
05209 }
05210 return x;
05211 }
05212
05213
05214
05215
05216
05217
05218
05219
05220
05221
05222 static int messagecount(const char *context, const char *mailbox, const char *folder)
05223 {
05224 struct odbc_obj *obj = NULL;
05225 int nummsgs = 0;
05226 int res;
05227 SQLHSTMT stmt = NULL;
05228 char sql[PATH_MAX];
05229 char rowdata[20];
05230 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05231 if (!folder)
05232 folder = "INBOX";
05233
05234 if (ast_strlen_zero(mailbox))
05235 return 0;
05236
05237 obj = ast_odbc_request_obj(odbc_database, 0);
05238 if (obj) {
05239 if (!strcmp(folder, "INBOX")) {
05240 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/INBOX' OR dir = '%s%s/%s/Urgent'", odbc_table, VM_SPOOL_DIR, context, mailbox, VM_SPOOL_DIR, context, mailbox);
05241 } else {
05242 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05243 }
05244 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05245 if (!stmt) {
05246 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05247 goto yuck;
05248 }
05249 res = SQLFetch(stmt);
05250 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05251 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05252 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05253 goto yuck;
05254 }
05255 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05256 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05257 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05258 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05259 goto yuck;
05260 }
05261 nummsgs = atoi(rowdata);
05262 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05263 } else
05264 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05265
05266 yuck:
05267 if (obj)
05268 ast_odbc_release_obj(obj);
05269 return nummsgs;
05270 }
05271
05272
05273
05274
05275
05276
05277
05278
05279
05280 static int has_voicemail(const char *mailbox, const char *folder)
05281 {
05282 char tmp[256], *tmp2 = tmp, *box, *context;
05283 ast_copy_string(tmp, mailbox, sizeof(tmp));
05284 while ((context = box = strsep(&tmp2, ",&"))) {
05285 strsep(&context, "@");
05286 if (ast_strlen_zero(context))
05287 context = "default";
05288 if (messagecount(context, box, folder))
05289 return 1;
05290 }
05291 return 0;
05292 }
05293 #endif
05294 #ifndef IMAP_STORAGE
05295
05296
05297
05298
05299
05300
05301
05302
05303
05304
05305
05306
05307
05308
05309
05310
05311 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)
05312 {
05313 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05314 const char *frombox = mbox(vmu, imbox);
05315 const char *userfolder;
05316 int recipmsgnum;
05317 int res = 0;
05318
05319 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05320
05321 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05322 userfolder = "Urgent";
05323 } else {
05324 userfolder = "INBOX";
05325 }
05326
05327 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05328
05329 if (!dir)
05330 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05331 else
05332 ast_copy_string(fromdir, dir, sizeof(fromdir));
05333
05334 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05335 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05336
05337 if (vm_lock_path(todir))
05338 return ERROR_LOCK_PATH;
05339
05340 recipmsgnum = last_message_index(recip, todir) + 1;
05341 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05342 make_file(topath, sizeof(topath), todir, recipmsgnum);
05343 #ifndef ODBC_STORAGE
05344 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05345 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05346 } else {
05347 #endif
05348
05349
05350
05351 copy_plain_file(frompath, topath);
05352 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05353 vm_delete(topath);
05354 #ifndef ODBC_STORAGE
05355 }
05356 #endif
05357 } else {
05358 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05359 res = -1;
05360 }
05361 ast_unlock_path(todir);
05362 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05363 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05364 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05365 flag);
05366
05367 return res;
05368 }
05369 #endif
05370 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05371
05372 static int messagecount(const char *context, const char *mailbox, const char *folder)
05373 {
05374 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05375 }
05376
05377 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05378 {
05379 DIR *dir;
05380 struct dirent *de;
05381 char fn[256];
05382 int ret = 0;
05383
05384
05385 if (ast_strlen_zero(mailbox))
05386 return 0;
05387
05388 if (ast_strlen_zero(folder))
05389 folder = "INBOX";
05390 if (ast_strlen_zero(context))
05391 context = "default";
05392
05393 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05394
05395 if (!(dir = opendir(fn)))
05396 return 0;
05397
05398 while ((de = readdir(dir))) {
05399 if (!strncasecmp(de->d_name, "msg", 3)) {
05400 if (shortcircuit) {
05401 ret = 1;
05402 break;
05403 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05404 ret++;
05405 }
05406 }
05407 }
05408
05409 closedir(dir);
05410
05411 return ret;
05412 }
05413
05414
05415
05416
05417
05418
05419
05420
05421
05422
05423 static int has_voicemail(const char *mailbox, const char *folder)
05424 {
05425 char tmp[256], *tmp2 = tmp, *box, *context;
05426 ast_copy_string(tmp, mailbox, sizeof(tmp));
05427 if (ast_strlen_zero(folder)) {
05428 folder = "INBOX";
05429 }
05430 while ((box = strsep(&tmp2, ",&"))) {
05431 if ((context = strchr(box, '@')))
05432 *context++ = '\0';
05433 else
05434 context = "default";
05435 if (__has_voicemail(context, box, folder, 1))
05436 return 1;
05437
05438 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05439 return 1;
05440 }
05441 }
05442 return 0;
05443 }
05444
05445
05446 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05447 {
05448 char tmp[256];
05449 char *context;
05450
05451
05452 if (ast_strlen_zero(mailbox))
05453 return 0;
05454
05455 if (newmsgs)
05456 *newmsgs = 0;
05457 if (oldmsgs)
05458 *oldmsgs = 0;
05459 if (urgentmsgs)
05460 *urgentmsgs = 0;
05461
05462 if (strchr(mailbox, ',')) {
05463 int tmpnew, tmpold, tmpurgent;
05464 char *mb, *cur;
05465
05466 ast_copy_string(tmp, mailbox, sizeof(tmp));
05467 mb = tmp;
05468 while ((cur = strsep(&mb, ", "))) {
05469 if (!ast_strlen_zero(cur)) {
05470 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05471 return -1;
05472 else {
05473 if (newmsgs)
05474 *newmsgs += tmpnew;
05475 if (oldmsgs)
05476 *oldmsgs += tmpold;
05477 if (urgentmsgs)
05478 *urgentmsgs += tmpurgent;
05479 }
05480 }
05481 }
05482 return 0;
05483 }
05484
05485 ast_copy_string(tmp, mailbox, sizeof(tmp));
05486
05487 if ((context = strchr(tmp, '@')))
05488 *context++ = '\0';
05489 else
05490 context = "default";
05491
05492 if (newmsgs)
05493 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05494 if (oldmsgs)
05495 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05496 if (urgentmsgs)
05497 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05498
05499 return 0;
05500 }
05501
05502 #endif
05503
05504
05505 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05506 {
05507 int urgentmsgs = 0;
05508 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05509 if (newmsgs) {
05510 *newmsgs += urgentmsgs;
05511 }
05512 return res;
05513 }
05514
05515 static void run_externnotify(char *context, char *extension, const char *flag)
05516 {
05517 char arguments[255];
05518 char ext_context[256] = "";
05519 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05520 struct ast_smdi_mwi_message *mwi_msg;
05521
05522 if (!ast_strlen_zero(context))
05523 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05524 else
05525 ast_copy_string(ext_context, extension, sizeof(ext_context));
05526
05527 if (smdi_iface) {
05528 if (ast_app_has_voicemail(ext_context, NULL))
05529 ast_smdi_mwi_set(smdi_iface, extension);
05530 else
05531 ast_smdi_mwi_unset(smdi_iface, extension);
05532
05533 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05534 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05535 if (!strncmp(mwi_msg->cause, "INV", 3))
05536 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05537 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05538 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05539 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05540 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05541 } else {
05542 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05543 }
05544 }
05545
05546 if (!ast_strlen_zero(externnotify)) {
05547 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05548 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05549 } else {
05550 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &", externnotify, context, extension, newvoicemails, oldvoicemails, urgentvoicemails);
05551 ast_debug(1, "Executing %s\n", arguments);
05552 ast_safe_system(arguments);
05553 }
05554 }
05555 }
05556
05557
05558
05559
05560
05561
05562 struct leave_vm_options {
05563 unsigned int flags;
05564 signed char record_gain;
05565 char *exitcontext;
05566 };
05567
05568
05569
05570
05571
05572
05573
05574
05575
05576
05577
05578 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05579 {
05580 #ifdef IMAP_STORAGE
05581 int newmsgs, oldmsgs;
05582 #else
05583 char urgdir[PATH_MAX];
05584 #endif
05585 char txtfile[PATH_MAX];
05586 char tmptxtfile[PATH_MAX];
05587 struct vm_state *vms = NULL;
05588 char callerid[256];
05589 FILE *txt;
05590 char date[256];
05591 int txtdes;
05592 int res = 0;
05593 int msgnum;
05594 int duration = 0;
05595 int sound_duration = 0;
05596 int ausemacro = 0;
05597 int ousemacro = 0;
05598 int ouseexten = 0;
05599 char tmpdur[16];
05600 char priority[16];
05601 char origtime[16];
05602 char dir[PATH_MAX];
05603 char tmpdir[PATH_MAX];
05604 char fn[PATH_MAX];
05605 char prefile[PATH_MAX] = "";
05606 char tempfile[PATH_MAX] = "";
05607 char ext_context[256] = "";
05608 char fmt[80];
05609 char *context;
05610 char ecodes[17] = "#";
05611 struct ast_str *tmp = ast_str_create(16);
05612 char *tmpptr;
05613 struct ast_vm_user *vmu;
05614 struct ast_vm_user svm;
05615 const char *category = NULL;
05616 const char *code;
05617 const char *alldtmf = "0123456789ABCD*#";
05618 char flag[80];
05619
05620 if (!tmp) {
05621 return -1;
05622 }
05623
05624 ast_str_set(&tmp, 0, "%s", ext);
05625 ext = ast_str_buffer(tmp);
05626 if ((context = strchr(ext, '@'))) {
05627 *context++ = '\0';
05628 tmpptr = strchr(context, '&');
05629 } else {
05630 tmpptr = strchr(ext, '&');
05631 }
05632
05633 if (tmpptr)
05634 *tmpptr++ = '\0';
05635
05636 ast_channel_lock(chan);
05637 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05638 category = ast_strdupa(category);
05639 }
05640 ast_channel_unlock(chan);
05641
05642 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05643 ast_copy_string(flag, "Urgent", sizeof(flag));
05644 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05645 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05646 } else {
05647 flag[0] = '\0';
05648 }
05649
05650 ast_debug(3, "Before find_user\n");
05651 if (!(vmu = find_user(&svm, context, ext))) {
05652 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05653 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05654 ast_free(tmp);
05655 return res;
05656 }
05657
05658 if (strcmp(vmu->context, "default"))
05659 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05660 else
05661 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05662
05663
05664
05665
05666
05667
05668 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05669 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05670 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05671 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05672 }
05673
05674
05675
05676
05677 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05678 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05679 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05680 ast_free(tmp);
05681 return -1;
05682 }
05683 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05684 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05685 ast_copy_string(prefile, tempfile, sizeof(prefile));
05686
05687 DISPOSE(tempfile, -1);
05688
05689 #ifndef IMAP_STORAGE
05690 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05691 #else
05692 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05693 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05694 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05695 }
05696 #endif
05697
05698
05699 if (ast_test_flag(vmu, VM_OPERATOR)) {
05700 if (!ast_strlen_zero(vmu->exit)) {
05701 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05702 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05703 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05704 ouseexten = 1;
05705 }
05706 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05707 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05708 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05709 ouseexten = 1;
05710 } else if (!ast_strlen_zero(chan->macrocontext)
05711 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05712 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05713 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05714 ousemacro = 1;
05715 }
05716 }
05717
05718 if (!ast_strlen_zero(vmu->exit)) {
05719 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05720 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05721 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05722 }
05723 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05724 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05725 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05726 } else if (!ast_strlen_zero(chan->macrocontext)
05727 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05728 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05729 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05730 ausemacro = 1;
05731 }
05732
05733 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05734 for (code = alldtmf; *code; code++) {
05735 char e[2] = "";
05736 e[0] = *code;
05737 if (strchr(ecodes, e[0]) == NULL
05738 && ast_canmatch_extension(chan,
05739 (!ast_strlen_zero(options->exitcontext) ? options->exitcontext : chan->context),
05740 e, 1, S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05741 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05742 }
05743 }
05744 }
05745
05746
05747 if (!ast_strlen_zero(prefile)) {
05748 #ifdef ODBC_STORAGE
05749 int success =
05750 #endif
05751 RETRIEVE(prefile, -1, ext, context);
05752 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05753 if (ast_streamfile(chan, prefile, chan->language) > -1)
05754 res = ast_waitstream(chan, ecodes);
05755 #ifdef ODBC_STORAGE
05756 if (success == -1) {
05757
05758 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05759 store_file(prefile, vmu->mailbox, vmu->context, -1);
05760 }
05761 #endif
05762 } else {
05763 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05764 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05765 }
05766 DISPOSE(prefile, -1);
05767 if (res < 0) {
05768 ast_debug(1, "Hang up during prefile playback\n");
05769 free_user(vmu);
05770 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05771 ast_free(tmp);
05772 return -1;
05773 }
05774 }
05775 if (res == '#') {
05776
05777 ast_set_flag(options, OPT_SILENT);
05778 res = 0;
05779 }
05780
05781 if (vmu->maxmsg == 0) {
05782 if (option_debug > 2)
05783 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05784 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05785 goto leave_vm_out;
05786 }
05787 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05788 res = ast_stream_and_wait(chan, INTRO, ecodes);
05789 if (res == '#') {
05790 ast_set_flag(options, OPT_SILENT);
05791 res = 0;
05792 }
05793 }
05794 if (res > 0)
05795 ast_stopstream(chan);
05796
05797
05798 if (res == '*') {
05799 chan->exten[0] = 'a';
05800 chan->exten[1] = '\0';
05801 if (!ast_strlen_zero(vmu->exit)) {
05802 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05803 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05804 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05805 }
05806 chan->priority = 0;
05807 free_user(vmu);
05808 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05809 ast_free(tmp);
05810 return 0;
05811 }
05812
05813
05814 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05815 transfer:
05816 if (ouseexten || ousemacro) {
05817 chan->exten[0] = 'o';
05818 chan->exten[1] = '\0';
05819 if (!ast_strlen_zero(vmu->exit)) {
05820 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05821 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05822 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05823 }
05824 ast_play_and_wait(chan, "transfer");
05825 chan->priority = 0;
05826 free_user(vmu);
05827 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05828 }
05829 ast_free(tmp);
05830 return OPERATOR_EXIT;
05831 }
05832
05833
05834 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05835 if (!ast_strlen_zero(options->exitcontext)) {
05836 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05837 }
05838 free_user(vmu);
05839 ast_free(tmp);
05840 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05841 return res;
05842 }
05843
05844 if (res < 0) {
05845 free_user(vmu);
05846 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05847 ast_free(tmp);
05848 return -1;
05849 }
05850
05851 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05852 if (!ast_strlen_zero(fmt)) {
05853 msgnum = 0;
05854
05855 #ifdef IMAP_STORAGE
05856
05857
05858 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05859 if (res < 0) {
05860 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05861 ast_free(tmp);
05862 return -1;
05863 }
05864 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05865
05866
05867
05868
05869 if (!(vms = create_vm_state_from_user(vmu))) {
05870 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05871 ast_free(tmp);
05872 return -1;
05873 }
05874 }
05875 vms->newmessages++;
05876
05877
05878 msgnum = newmsgs + oldmsgs;
05879 ast_debug(3, "Messagecount set to %d\n", msgnum);
05880 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05881
05882 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05883
05884 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05885 goto leave_vm_out;
05886 }
05887 #else
05888 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05889 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05890 if (!res)
05891 res = ast_waitstream(chan, "");
05892 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05893 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05894 inprocess_count(vmu->mailbox, vmu->context, -1);
05895 goto leave_vm_out;
05896 }
05897
05898 #endif
05899 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05900 txtdes = mkstemp(tmptxtfile);
05901 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05902 if (txtdes < 0) {
05903 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05904 if (!res)
05905 res = ast_waitstream(chan, "");
05906 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05907 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05908 inprocess_count(vmu->mailbox, vmu->context, -1);
05909 goto leave_vm_out;
05910 }
05911
05912
05913 if (res >= 0) {
05914
05915 res = ast_stream_and_wait(chan, "beep", "");
05916 }
05917
05918
05919 if (ast_check_realtime("voicemail_data")) {
05920 snprintf(priority, sizeof(priority), "%d", chan->priority);
05921 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05922 get_date(date, sizeof(date));
05923 ast_callerid_merge(callerid, sizeof(callerid),
05924 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05925 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05926 "Unknown");
05927 ast_store_realtime("voicemail_data",
05928 "origmailbox", ext,
05929 "context", chan->context,
05930 "macrocontext", chan->macrocontext,
05931 "exten", chan->exten,
05932 "priority", priority,
05933 "callerchan", chan->name,
05934 "callerid", callerid,
05935 "origdate", date,
05936 "origtime", origtime,
05937 "category", S_OR(category, ""),
05938 "filename", tmptxtfile,
05939 SENTINEL);
05940 }
05941
05942
05943 txt = fdopen(txtdes, "w+");
05944 if (txt) {
05945 get_date(date, sizeof(date));
05946 ast_callerid_merge(callerid, sizeof(callerid),
05947 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05948 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05949 "Unknown");
05950 fprintf(txt,
05951 ";\n"
05952 "; Message Information file\n"
05953 ";\n"
05954 "[message]\n"
05955 "origmailbox=%s\n"
05956 "context=%s\n"
05957 "macrocontext=%s\n"
05958 "exten=%s\n"
05959 "rdnis=%s\n"
05960 "priority=%d\n"
05961 "callerchan=%s\n"
05962 "callerid=%s\n"
05963 "origdate=%s\n"
05964 "origtime=%ld\n"
05965 "category=%s\n",
05966 ext,
05967 chan->context,
05968 chan->macrocontext,
05969 chan->exten,
05970 S_COR(chan->redirecting.from.number.valid,
05971 chan->redirecting.from.number.str, "unknown"),
05972 chan->priority,
05973 chan->name,
05974 callerid,
05975 date, (long) time(NULL),
05976 category ? category : "");
05977 } else {
05978 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
05979 inprocess_count(vmu->mailbox, vmu->context, -1);
05980 if (ast_check_realtime("voicemail_data")) {
05981 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05982 }
05983 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05984 goto leave_vm_out;
05985 }
05986 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag);
05987
05988 if (txt) {
05989 fprintf(txt, "flag=%s\n", flag);
05990 if (sound_duration < vmu->minsecs) {
05991 fclose(txt);
05992 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
05993 ast_filedelete(tmptxtfile, NULL);
05994 unlink(tmptxtfile);
05995 if (ast_check_realtime("voicemail_data")) {
05996 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
05997 }
05998 inprocess_count(vmu->mailbox, vmu->context, -1);
05999 } else {
06000 fprintf(txt, "duration=%d\n", duration);
06001 fclose(txt);
06002 if (vm_lock_path(dir)) {
06003 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
06004
06005 ast_filedelete(tmptxtfile, NULL);
06006 unlink(tmptxtfile);
06007 inprocess_count(vmu->mailbox, vmu->context, -1);
06008 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
06009 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
06010 unlink(tmptxtfile);
06011 ast_unlock_path(dir);
06012 inprocess_count(vmu->mailbox, vmu->context, -1);
06013 if (ast_check_realtime("voicemail_data")) {
06014 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06015 }
06016 } else {
06017 #ifndef IMAP_STORAGE
06018 msgnum = last_message_index(vmu, dir) + 1;
06019 #endif
06020 make_file(fn, sizeof(fn), dir, msgnum);
06021
06022
06023 #ifndef IMAP_STORAGE
06024 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
06025 #else
06026 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06027 #endif
06028
06029 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
06030 ast_filerename(tmptxtfile, fn, NULL);
06031 rename(tmptxtfile, txtfile);
06032 inprocess_count(vmu->mailbox, vmu->context, -1);
06033
06034
06035
06036 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
06037 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
06038
06039 ast_unlock_path(dir);
06040 if (ast_check_realtime("voicemail_data")) {
06041 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
06042 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
06043 }
06044
06045
06046
06047 if (ast_fileexists(fn, NULL, NULL) > 0) {
06048 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
06049 }
06050
06051
06052 while (tmpptr) {
06053 struct ast_vm_user recipu, *recip;
06054 char *exten, *cntx;
06055
06056 exten = strsep(&tmpptr, "&");
06057 cntx = strchr(exten, '@');
06058 if (cntx) {
06059 *cntx = '\0';
06060 cntx++;
06061 }
06062 if ((recip = find_user(&recipu, cntx, exten))) {
06063 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
06064 free_user(recip);
06065 }
06066 }
06067 #ifndef IMAP_STORAGE
06068 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06069
06070 char sfn[PATH_MAX];
06071 char dfn[PATH_MAX];
06072 int x;
06073
06074 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
06075 x = last_message_index(vmu, urgdir) + 1;
06076 make_file(sfn, sizeof(sfn), dir, msgnum);
06077 make_file(dfn, sizeof(dfn), urgdir, x);
06078 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
06079 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
06080
06081 ast_copy_string(fn, dfn, sizeof(fn));
06082 msgnum = x;
06083 }
06084 #endif
06085
06086 if (ast_fileexists(fn, NULL, NULL)) {
06087 #ifdef IMAP_STORAGE
06088 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
06089 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06090 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06091 flag);
06092 #else
06093 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
06094 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06095 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06096 flag);
06097 #endif
06098 }
06099
06100
06101 if (ast_fileexists(fn, NULL, NULL)) {
06102 DISPOSE(dir, msgnum);
06103 }
06104 }
06105 }
06106 } else {
06107 inprocess_count(vmu->mailbox, vmu->context, -1);
06108 }
06109 if (res == '0') {
06110 goto transfer;
06111 } else if (res > 0 && res != 't')
06112 res = 0;
06113
06114 if (sound_duration < vmu->minsecs)
06115
06116 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06117 else
06118 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06119 } else
06120 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06121 leave_vm_out:
06122 free_user(vmu);
06123
06124 #ifdef IMAP_STORAGE
06125
06126 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06127 if (expungeonhangup == 1) {
06128 ast_mutex_lock(&vms->lock);
06129 #ifdef HAVE_IMAP_TK2006
06130 if (LEVELUIDPLUS (vms->mailstream)) {
06131 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06132 } else
06133 #endif
06134 mail_expunge(vms->mailstream);
06135 ast_mutex_unlock(&vms->lock);
06136 }
06137 #endif
06138
06139 ast_free(tmp);
06140 return res;
06141 }
06142
06143 #if !defined(IMAP_STORAGE)
06144 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06145 {
06146
06147
06148 int x, dest;
06149 char sfn[PATH_MAX];
06150 char dfn[PATH_MAX];
06151
06152 if (vm_lock_path(dir)) {
06153 return ERROR_LOCK_PATH;
06154 }
06155
06156 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06157 make_file(sfn, sizeof(sfn), dir, x);
06158 if (EXISTS(dir, x, sfn, NULL)) {
06159
06160 if (x != dest) {
06161 make_file(dfn, sizeof(dfn), dir, dest);
06162 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06163 }
06164
06165 dest++;
06166 }
06167 }
06168 ast_unlock_path(dir);
06169
06170 return dest;
06171 }
06172 #endif
06173
06174 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06175 {
06176 int d;
06177 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06178 return d;
06179 }
06180
06181 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06182 {
06183 #ifdef IMAP_STORAGE
06184
06185
06186 char sequence[10];
06187 char mailbox[256];
06188 int res;
06189
06190
06191 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06192
06193 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06194 ast_mutex_lock(&vms->lock);
06195
06196 if (box == OLD_FOLDER) {
06197 mail_setflag(vms->mailstream, sequence, "\\Seen");
06198 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06199 } else if (box == NEW_FOLDER) {
06200 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06201 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06202 }
06203 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06204 ast_mutex_unlock(&vms->lock);
06205 return 0;
06206 }
06207
06208 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06209 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06210 if (mail_create(vms->mailstream, mailbox) == NIL)
06211 ast_debug(5, "Folder exists.\n");
06212 else
06213 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06214 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06215 ast_mutex_unlock(&vms->lock);
06216 return res;
06217 #else
06218 char *dir = vms->curdir;
06219 char *username = vms->username;
06220 char *context = vmu->context;
06221 char sfn[PATH_MAX];
06222 char dfn[PATH_MAX];
06223 char ddir[PATH_MAX];
06224 const char *dbox = mbox(vmu, box);
06225 int x, i;
06226 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06227
06228 if (vm_lock_path(ddir))
06229 return ERROR_LOCK_PATH;
06230
06231 x = last_message_index(vmu, ddir) + 1;
06232
06233 if (box == 10 && x >= vmu->maxdeletedmsg) {
06234 x--;
06235 for (i = 1; i <= x; i++) {
06236
06237 make_file(sfn, sizeof(sfn), ddir, i);
06238 make_file(dfn, sizeof(dfn), ddir, i - 1);
06239 if (EXISTS(ddir, i, sfn, NULL)) {
06240 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06241 } else
06242 break;
06243 }
06244 } else {
06245 if (x >= vmu->maxmsg) {
06246 ast_unlock_path(ddir);
06247 return -1;
06248 }
06249 }
06250 make_file(sfn, sizeof(sfn), dir, msg);
06251 make_file(dfn, sizeof(dfn), ddir, x);
06252 if (strcmp(sfn, dfn)) {
06253 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06254 }
06255 ast_unlock_path(ddir);
06256 #endif
06257 return 0;
06258 }
06259
06260 static int adsi_logo(unsigned char *buf)
06261 {
06262 int bytes = 0;
06263 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06264 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06265 return bytes;
06266 }
06267
06268 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06269 {
06270 unsigned char buf[256];
06271 int bytes = 0;
06272 int x;
06273 char num[5];
06274
06275 *useadsi = 0;
06276 bytes += ast_adsi_data_mode(buf + bytes);
06277 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06278
06279 bytes = 0;
06280 bytes += adsi_logo(buf);
06281 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06282 #ifdef DISPLAY
06283 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06284 #endif
06285 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06286 bytes += ast_adsi_data_mode(buf + bytes);
06287 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06288
06289 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06290 bytes = 0;
06291 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06292 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06293 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06294 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06295 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06296 return 0;
06297 }
06298
06299 #ifdef DISPLAY
06300
06301 bytes = 0;
06302 bytes += ast_adsi_logo(buf);
06303 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06304 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06305 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06306 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06307 #endif
06308 bytes = 0;
06309 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06310 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06311 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06312 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06313 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06314 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06315 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06316
06317 #ifdef DISPLAY
06318
06319 bytes = 0;
06320 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06321 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06322
06323 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06324 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06325 #endif
06326
06327 bytes = 0;
06328
06329 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06330 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06331 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06332 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06333 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06334 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06335 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06336
06337 #ifdef DISPLAY
06338
06339 bytes = 0;
06340 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06341 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06342 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06343 #endif
06344
06345 bytes = 0;
06346 for (x = 0; x < 5; x++) {
06347 snprintf(num, sizeof(num), "%d", x);
06348 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06349 }
06350 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06351 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06352
06353 #ifdef DISPLAY
06354
06355 bytes = 0;
06356 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06357 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06358 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06359 #endif
06360
06361 if (ast_adsi_end_download(chan)) {
06362 bytes = 0;
06363 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06364 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06365 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06366 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06367 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06368 return 0;
06369 }
06370 bytes = 0;
06371 bytes += ast_adsi_download_disconnect(buf + bytes);
06372 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06373 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06374
06375 ast_debug(1, "Done downloading scripts...\n");
06376
06377 #ifdef DISPLAY
06378
06379 bytes = 0;
06380 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06381 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06382 #endif
06383 ast_debug(1, "Restarting session...\n");
06384
06385 bytes = 0;
06386
06387 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06388 *useadsi = 1;
06389 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06390 } else
06391 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06392
06393 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06394 return 0;
06395 }
06396
06397 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06398 {
06399 int x;
06400 if (!ast_adsi_available(chan))
06401 return;
06402 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06403 if (x < 0)
06404 return;
06405 if (!x) {
06406 if (adsi_load_vmail(chan, useadsi)) {
06407 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06408 return;
06409 }
06410 } else
06411 *useadsi = 1;
06412 }
06413
06414 static void adsi_login(struct ast_channel *chan)
06415 {
06416 unsigned char buf[256];
06417 int bytes = 0;
06418 unsigned char keys[8];
06419 int x;
06420 if (!ast_adsi_available(chan))
06421 return;
06422
06423 for (x = 0; x < 8; x++)
06424 keys[x] = 0;
06425
06426 keys[3] = ADSI_KEY_APPS + 3;
06427
06428 bytes += adsi_logo(buf + bytes);
06429 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06430 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06431 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06432 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06433 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06434 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06435 bytes += ast_adsi_set_keys(buf + bytes, keys);
06436 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06437 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06438 }
06439
06440 static void adsi_password(struct ast_channel *chan)
06441 {
06442 unsigned char buf[256];
06443 int bytes = 0;
06444 unsigned char keys[8];
06445 int x;
06446 if (!ast_adsi_available(chan))
06447 return;
06448
06449 for (x = 0; x < 8; x++)
06450 keys[x] = 0;
06451
06452 keys[3] = ADSI_KEY_APPS + 3;
06453
06454 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06455 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06456 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06457 bytes += ast_adsi_set_keys(buf + bytes, keys);
06458 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06459 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06460 }
06461
06462 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06463 {
06464 unsigned char buf[256];
06465 int bytes = 0;
06466 unsigned char keys[8];
06467 int x, y;
06468
06469 if (!ast_adsi_available(chan))
06470 return;
06471
06472 for (x = 0; x < 5; x++) {
06473 y = ADSI_KEY_APPS + 12 + start + x;
06474 if (y > ADSI_KEY_APPS + 12 + 4)
06475 y = 0;
06476 keys[x] = ADSI_KEY_SKT | y;
06477 }
06478 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06479 keys[6] = 0;
06480 keys[7] = 0;
06481
06482 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06483 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06484 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06485 bytes += ast_adsi_set_keys(buf + bytes, keys);
06486 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06487
06488 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06489 }
06490
06491 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06492 {
06493 int bytes = 0;
06494 unsigned char buf[256];
06495 char buf1[256], buf2[256];
06496 char fn2[PATH_MAX];
06497
06498 char cid[256] = "";
06499 char *val;
06500 char *name, *num;
06501 char datetime[21] = "";
06502 FILE *f;
06503
06504 unsigned char keys[8];
06505
06506 int x;
06507
06508 if (!ast_adsi_available(chan))
06509 return;
06510
06511
06512 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06513 f = fopen(fn2, "r");
06514 if (f) {
06515 while (!feof(f)) {
06516 if (!fgets((char *) buf, sizeof(buf), f)) {
06517 continue;
06518 }
06519 if (!feof(f)) {
06520 char *stringp = NULL;
06521 stringp = (char *) buf;
06522 strsep(&stringp, "=");
06523 val = strsep(&stringp, "=");
06524 if (!ast_strlen_zero(val)) {
06525 if (!strcmp((char *) buf, "callerid"))
06526 ast_copy_string(cid, val, sizeof(cid));
06527 if (!strcmp((char *) buf, "origdate"))
06528 ast_copy_string(datetime, val, sizeof(datetime));
06529 }
06530 }
06531 }
06532 fclose(f);
06533 }
06534
06535 for (x = 0; x < 5; x++)
06536 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06537 keys[6] = 0x0;
06538 keys[7] = 0x0;
06539
06540 if (!vms->curmsg) {
06541
06542 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06543 }
06544 if (vms->curmsg >= vms->lastmsg) {
06545
06546 if (vms->curmsg) {
06547
06548 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06549 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06550
06551 } else {
06552
06553 keys[3] = 1;
06554 }
06555 }
06556
06557 if (!ast_strlen_zero(cid)) {
06558 ast_callerid_parse(cid, &name, &num);
06559 if (!name)
06560 name = num;
06561 } else
06562 name = "Unknown Caller";
06563
06564
06565 #ifdef IMAP_STORAGE
06566 ast_mutex_lock(&vms->lock);
06567 #endif
06568 if (vms->deleted[vms->curmsg]) {
06569 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06570 }
06571 #ifdef IMAP_STORAGE
06572 ast_mutex_unlock(&vms->lock);
06573 #endif
06574
06575
06576 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06577 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06578 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06579 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06580
06581 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06582 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06583 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06584 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06585 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06586 bytes += ast_adsi_set_keys(buf + bytes, keys);
06587 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06588
06589 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06590 }
06591
06592 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06593 {
06594 int bytes = 0;
06595 unsigned char buf[256];
06596 unsigned char keys[8];
06597
06598 int x;
06599
06600 if (!ast_adsi_available(chan))
06601 return;
06602
06603
06604 for (x = 0; x < 5; x++)
06605 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06606
06607 keys[6] = 0x0;
06608 keys[7] = 0x0;
06609
06610 if (!vms->curmsg) {
06611
06612 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06613 }
06614 if (vms->curmsg >= vms->lastmsg) {
06615
06616 if (vms->curmsg) {
06617
06618 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06619 } else {
06620
06621 keys[3] = 1;
06622 }
06623 }
06624
06625
06626 #ifdef IMAP_STORAGE
06627 ast_mutex_lock(&vms->lock);
06628 #endif
06629 if (vms->deleted[vms->curmsg]) {
06630 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06631 }
06632 #ifdef IMAP_STORAGE
06633 ast_mutex_unlock(&vms->lock);
06634 #endif
06635
06636
06637 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06638 bytes += ast_adsi_set_keys(buf + bytes, keys);
06639 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06640
06641 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06642 }
06643
06644 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06645 {
06646 unsigned char buf[256] = "";
06647 char buf1[256] = "", buf2[256] = "";
06648 int bytes = 0;
06649 unsigned char keys[8];
06650 int x;
06651
06652 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06653 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06654 if (!ast_adsi_available(chan))
06655 return;
06656 if (vms->newmessages) {
06657 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06658 if (vms->oldmessages) {
06659 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06660 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06661 } else {
06662 snprintf(buf2, sizeof(buf2), "%s.", newm);
06663 }
06664 } else if (vms->oldmessages) {
06665 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06666 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06667 } else {
06668 strcpy(buf1, "You have no messages.");
06669 buf2[0] = ' ';
06670 buf2[1] = '\0';
06671 }
06672 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06673 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06674 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06675
06676 for (x = 0; x < 6; x++)
06677 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06678 keys[6] = 0;
06679 keys[7] = 0;
06680
06681
06682 if (vms->lastmsg < 0)
06683 keys[0] = 1;
06684 bytes += ast_adsi_set_keys(buf + bytes, keys);
06685
06686 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06687
06688 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06689 }
06690
06691 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06692 {
06693 unsigned char buf[256] = "";
06694 char buf1[256] = "", buf2[256] = "";
06695 int bytes = 0;
06696 unsigned char keys[8];
06697 int x;
06698
06699 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06700
06701 if (!ast_adsi_available(chan))
06702 return;
06703
06704
06705 for (x = 0; x < 6; x++)
06706 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06707
06708 keys[6] = 0;
06709 keys[7] = 0;
06710
06711 if ((vms->lastmsg + 1) < 1)
06712 keys[0] = 0;
06713
06714 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06715 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06716
06717 if (vms->lastmsg + 1)
06718 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06719 else
06720 strcpy(buf2, "no messages.");
06721 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06722 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06723 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06724 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06725 bytes += ast_adsi_set_keys(buf + bytes, keys);
06726
06727 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06728
06729 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06730
06731 }
06732
06733
06734
06735
06736
06737
06738
06739
06740
06741
06742
06743
06744
06745
06746
06747 static void adsi_goodbye(struct ast_channel *chan)
06748 {
06749 unsigned char buf[256];
06750 int bytes = 0;
06751
06752 if (!ast_adsi_available(chan))
06753 return;
06754 bytes += adsi_logo(buf + bytes);
06755 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06756 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06757 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06758 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06759
06760 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06761 }
06762
06763
06764
06765
06766
06767 static int get_folder(struct ast_channel *chan, int start)
06768 {
06769 int x;
06770 int d;
06771 char fn[PATH_MAX];
06772 d = ast_play_and_wait(chan, "vm-press");
06773 if (d)
06774 return d;
06775 for (x = start; x < 5; x++) {
06776 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06777 return d;
06778 d = ast_play_and_wait(chan, "vm-for");
06779 if (d)
06780 return d;
06781 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06782
06783
06784
06785
06786 if (x == 0) {
06787 if (ast_fileexists(fn, NULL, NULL)) {
06788 d = vm_play_folder_name(chan, fn);
06789 } else {
06790 ast_verb(1, "failed to find %s\n", fn);
06791 d = vm_play_folder_name(chan, "vm-INBOX");
06792 }
06793 } else {
06794 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
06795 d = vm_play_folder_name(chan, fn);
06796 }
06797
06798 if (d)
06799 return d;
06800 d = ast_waitfordigit(chan, 500);
06801 if (d)
06802 return d;
06803 }
06804
06805 d = ast_play_and_wait(chan, "vm-tocancel");
06806 if (d)
06807 return d;
06808 d = ast_waitfordigit(chan, 4000);
06809 return d;
06810 }
06811
06812
06813
06814
06815
06816
06817
06818
06819
06820
06821
06822
06823
06824 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06825 {
06826 int res = 0;
06827 int loops = 0;
06828
06829 res = ast_play_and_wait(chan, fn);
06830 while (((res < '0') || (res > '9')) &&
06831 (res != '#') && (res >= 0) &&
06832 loops < 4) {
06833 res = get_folder(chan, 0);
06834 loops++;
06835 }
06836 if (loops == 4) {
06837 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
06838 return '#';
06839 }
06840 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
06841 return res;
06842 }
06843
06844
06845
06846
06847
06848
06849
06850
06851
06852
06853
06854
06855
06856
06857
06858
06859
06860
06861
06862 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06863 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06864 {
06865 int cmd = 0;
06866 int retries = 0, prepend_duration = 0, already_recorded = 0;
06867 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06868 char textfile[PATH_MAX];
06869 struct ast_config *msg_cfg;
06870 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06871 #ifndef IMAP_STORAGE
06872 signed char zero_gain = 0;
06873 #endif
06874 const char *duration_str;
06875
06876
06877 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06878 strcpy(textfile, msgfile);
06879 strcpy(backup, msgfile);
06880 strcpy(backup_textfile, msgfile);
06881 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06882 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06883 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06884
06885 if ((msg_cfg = ast_config_load(textfile, config_flags)) && msg_cfg != CONFIG_STATUS_FILEINVALID && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06886 *duration = atoi(duration_str);
06887 } else {
06888 *duration = 0;
06889 }
06890
06891 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06892 if (cmd)
06893 retries = 0;
06894 switch (cmd) {
06895 case '1':
06896
06897 #ifdef IMAP_STORAGE
06898
06899 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06900 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06901 ast_play_and_wait(chan, INTRO);
06902 ast_play_and_wait(chan, "beep");
06903 cmd = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag);
06904 if (cmd == -1) {
06905 break;
06906 }
06907 cmd = 't';
06908 #else
06909
06910
06911
06912 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06913 strcpy(textfile, msgfile);
06914 strncat(textfile, ".txt", sizeof(textfile) - 1);
06915 *duration = 0;
06916
06917
06918 if (!msg_cfg) {
06919 cmd = 0;
06920 break;
06921 }
06922
06923
06924 #ifndef IMAP_STORAGE
06925 if (already_recorded) {
06926 ast_filecopy(backup, msgfile, NULL);
06927 copy(backup_textfile, textfile);
06928 }
06929 else {
06930 ast_filecopy(msgfile, backup, NULL);
06931 copy(textfile, backup_textfile);
06932 }
06933 #endif
06934 already_recorded = 1;
06935
06936 if (record_gain)
06937 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06938
06939 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
06940
06941 if (cmd == 'S') {
06942 ast_stream_and_wait(chan, vm_pls_try_again, "");
06943 ast_stream_and_wait(chan, vm_prepend_timeout, "");
06944 ast_filerename(backup, msgfile, NULL);
06945 }
06946
06947 if (record_gain)
06948 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06949
06950
06951 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06952 *duration = atoi(duration_str);
06953
06954 if (prepend_duration) {
06955 struct ast_category *msg_cat;
06956
06957 char duration_buf[12];
06958
06959 *duration += prepend_duration;
06960 msg_cat = ast_category_get(msg_cfg, "message");
06961 snprintf(duration_buf, 11, "%ld", *duration);
06962 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06963 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
06964 }
06965 }
06966
06967 #endif
06968 break;
06969 case '2':
06970
06971 #ifdef IMAP_STORAGE
06972 *vms->introfn = '\0';
06973 #endif
06974 cmd = 't';
06975 break;
06976 case '*':
06977 cmd = '*';
06978 break;
06979 default:
06980
06981 already_recorded = 0;
06982
06983 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
06984
06985 if (!cmd) {
06986 cmd = ast_play_and_wait(chan, "vm-starmain");
06987
06988 }
06989 if (!cmd) {
06990 cmd = ast_waitfordigit(chan, 6000);
06991 }
06992 if (!cmd) {
06993 retries++;
06994 }
06995 if (retries > 3) {
06996 cmd = '*';
06997 }
06998 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
06999 }
07000 }
07001
07002 if (msg_cfg)
07003 ast_config_destroy(msg_cfg);
07004 if (prepend_duration)
07005 *duration = prepend_duration;
07006
07007 if (already_recorded && cmd == -1) {
07008
07009 ast_filerename(backup, msgfile, NULL);
07010 rename(backup_textfile, textfile);
07011 }
07012
07013 if (cmd == 't' || cmd == 'S')
07014 cmd = 0;
07015 return cmd;
07016 }
07017
07018 static void queue_mwi_event(const char *box, int urgent, int new, int old)
07019 {
07020 struct ast_event *event;
07021 char *mailbox, *context;
07022
07023
07024 context = mailbox = ast_strdupa(box);
07025 strsep(&context, "@");
07026 if (ast_strlen_zero(context))
07027 context = "default";
07028
07029 if (!(event = ast_event_new(AST_EVENT_MWI,
07030 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
07031 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
07032 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
07033 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
07034 AST_EVENT_IE_END))) {
07035 return;
07036 }
07037
07038 ast_event_queue_and_cache(event);
07039 }
07040
07041
07042
07043
07044
07045
07046
07047
07048
07049
07050
07051
07052
07053
07054
07055 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)
07056 {
07057 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
07058 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
07059 const char *category;
07060 char *myserveremail = serveremail;
07061
07062 ast_channel_lock(chan);
07063 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
07064 category = ast_strdupa(category);
07065 }
07066 ast_channel_unlock(chan);
07067
07068 #ifndef IMAP_STORAGE
07069 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
07070 #else
07071 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
07072 #endif
07073 make_file(fn, sizeof(fn), todir, msgnum);
07074 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
07075
07076 if (!ast_strlen_zero(vmu->attachfmt)) {
07077 if (strstr(fmt, vmu->attachfmt))
07078 fmt = vmu->attachfmt;
07079 else
07080 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);
07081 }
07082
07083
07084 fmt = ast_strdupa(fmt);
07085 stringp = fmt;
07086 strsep(&stringp, "|");
07087
07088 if (!ast_strlen_zero(vmu->serveremail))
07089 myserveremail = vmu->serveremail;
07090
07091 if (!ast_strlen_zero(vmu->email)) {
07092 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
07093
07094 if (attach_user_voicemail)
07095 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
07096
07097
07098 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
07099
07100 if (attach_user_voicemail)
07101 DISPOSE(todir, msgnum);
07102 }
07103
07104 if (!ast_strlen_zero(vmu->pager)) {
07105 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
07106 }
07107
07108 if (ast_test_flag(vmu, VM_DELETE))
07109 DELETE(todir, msgnum, fn, vmu);
07110
07111
07112 if (ast_app_has_voicemail(ext_context, NULL))
07113 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
07114
07115 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
07116
07117 ast_manager_event(chan, 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);
07118 run_externnotify(vmu->context, vmu->mailbox, flag);
07119
07120 #ifdef IMAP_STORAGE
07121 vm_delete(fn);
07122 if (ast_test_flag(vmu, VM_DELETE)) {
07123 vm_imap_delete(NULL, vms->curmsg, vmu);
07124 vms->newmessages--;
07125 }
07126 #endif
07127
07128 return 0;
07129 }
07130
07131
07132
07133
07134
07135
07136
07137
07138
07139
07140
07141
07142
07143
07144
07145
07146
07147
07148
07149
07150
07151
07152
07153
07154
07155
07156
07157
07158 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)
07159 {
07160 #ifdef IMAP_STORAGE
07161 int todircount = 0;
07162 struct vm_state *dstvms;
07163 #endif
07164 char username[70]="";
07165 char fn[PATH_MAX];
07166 char ecodes[16] = "#";
07167 int res = 0, cmd = 0;
07168 struct ast_vm_user *receiver = NULL, *vmtmp;
07169 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
07170 char *stringp;
07171 const char *s;
07172 int saved_messages = 0;
07173 int valid_extensions = 0;
07174 char *dir;
07175 int curmsg;
07176 char urgent_str[7] = "";
07177 int prompt_played = 0;
07178 #ifndef IMAP_STORAGE
07179 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07180 #endif
07181 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07182 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07183 }
07184
07185 if (vms == NULL) return -1;
07186 dir = vms->curdir;
07187 curmsg = vms->curmsg;
07188
07189 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
07190 while (!res && !valid_extensions) {
07191 int use_directory = 0;
07192 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07193 int done = 0;
07194 int retries = 0;
07195 cmd = 0;
07196 while ((cmd >= 0) && !done ){
07197 if (cmd)
07198 retries = 0;
07199 switch (cmd) {
07200 case '1':
07201 use_directory = 0;
07202 done = 1;
07203 break;
07204 case '2':
07205 use_directory = 1;
07206 done = 1;
07207 break;
07208 case '*':
07209 cmd = 't';
07210 done = 1;
07211 break;
07212 default:
07213
07214 cmd = ast_play_and_wait(chan, "vm-forward");
07215 if (!cmd) {
07216 cmd = ast_waitfordigit(chan, 3000);
07217 }
07218 if (!cmd) {
07219 retries++;
07220 }
07221 if (retries > 3) {
07222 cmd = 't';
07223 done = 1;
07224 }
07225 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07226 }
07227 }
07228 if (cmd < 0 || cmd == 't')
07229 break;
07230 }
07231
07232 if (use_directory) {
07233
07234
07235 char old_context[sizeof(chan->context)];
07236 char old_exten[sizeof(chan->exten)];
07237 int old_priority;
07238 struct ast_app* directory_app;
07239
07240 directory_app = pbx_findapp("Directory");
07241 if (directory_app) {
07242 char vmcontext[256];
07243
07244 memcpy(old_context, chan->context, sizeof(chan->context));
07245 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07246 old_priority = chan->priority;
07247
07248
07249 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07250 res = pbx_exec(chan, directory_app, vmcontext);
07251
07252 ast_copy_string(username, chan->exten, sizeof(username));
07253
07254
07255 memcpy(chan->context, old_context, sizeof(chan->context));
07256 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07257 chan->priority = old_priority;
07258 } else {
07259 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07260 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07261 }
07262 } else {
07263
07264 ast_test_suite_event_notify("PLAYBACK", "Message: vm-extension");
07265 res = ast_streamfile(chan, "vm-extension", chan->language);
07266 prompt_played++;
07267 if (res || prompt_played > 4)
07268 break;
07269 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07270 break;
07271 }
07272
07273
07274 if (ast_strlen_zero(username))
07275 continue;
07276 stringp = username;
07277 s = strsep(&stringp, "*");
07278
07279 valid_extensions = 1;
07280 while (s) {
07281 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07282 int oldmsgs;
07283 int newmsgs;
07284 int capacity;
07285 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07286 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07287
07288 res = ast_play_and_wait(chan, "pbx-invalid");
07289 valid_extensions = 0;
07290 break;
07291 }
07292 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07293 if ((newmsgs + oldmsgs) >= capacity) {
07294 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07295 res = ast_play_and_wait(chan, "vm-mailboxfull");
07296 valid_extensions = 0;
07297 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07298 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07299 free_user(vmtmp);
07300 }
07301 inprocess_count(receiver->mailbox, receiver->context, -1);
07302 break;
07303 }
07304 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07305 } else {
07306
07307
07308
07309
07310
07311 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07312 free_user(receiver);
07313 }
07314 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07315
07316 res = ast_play_and_wait(chan, "pbx-invalid");
07317 valid_extensions = 0;
07318 break;
07319 }
07320
07321
07322 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07323 RETRIEVE(fn, -1, s, receiver->context);
07324 if (ast_fileexists(fn, NULL, NULL) > 0) {
07325 res = ast_stream_and_wait(chan, fn, ecodes);
07326 if (res) {
07327 DISPOSE(fn, -1);
07328 return res;
07329 }
07330 } else {
07331 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07332 }
07333 DISPOSE(fn, -1);
07334
07335 s = strsep(&stringp, "*");
07336 }
07337
07338 if (valid_extensions)
07339 break;
07340 }
07341
07342 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07343 return res;
07344 if (is_new_message == 1) {
07345 struct leave_vm_options leave_options;
07346 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07347 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07348
07349
07350 memset(&leave_options, 0, sizeof(leave_options));
07351 leave_options.record_gain = record_gain;
07352 cmd = leave_voicemail(chan, mailbox, &leave_options);
07353 } else {
07354
07355 long duration = 0;
07356 struct vm_state vmstmp;
07357 int copy_msg_result = 0;
07358 memcpy(&vmstmp, vms, sizeof(vmstmp));
07359
07360 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07361
07362 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07363 if (!cmd) {
07364 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07365 #ifdef IMAP_STORAGE
07366 int attach_user_voicemail;
07367 char *myserveremail = serveremail;
07368
07369
07370 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07371 if (!dstvms) {
07372 dstvms = create_vm_state_from_user(vmtmp);
07373 }
07374 if (dstvms) {
07375 init_mailstream(dstvms, 0);
07376 if (!dstvms->mailstream) {
07377 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07378 } else {
07379 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07380 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07381 }
07382 } else {
07383 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07384 }
07385 if (!ast_strlen_zero(vmtmp->serveremail))
07386 myserveremail = vmtmp->serveremail;
07387 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07388
07389 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07390 dstvms->curbox,
07391 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07392 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07393 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07394 NULL, urgent_str);
07395 #else
07396 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07397 #endif
07398 saved_messages++;
07399 AST_LIST_REMOVE_CURRENT(list);
07400 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07401 free_user(vmtmp);
07402 if (res)
07403 break;
07404 }
07405 AST_LIST_TRAVERSE_SAFE_END;
07406 if (saved_messages > 0 && !copy_msg_result) {
07407
07408
07409
07410
07411
07412
07413
07414
07415 #ifdef IMAP_STORAGE
07416
07417 if (ast_strlen_zero(vmstmp.introfn))
07418 #endif
07419 res = ast_play_and_wait(chan, "vm-msgsaved");
07420 }
07421 #ifndef IMAP_STORAGE
07422 else {
07423
07424 res = ast_play_and_wait(chan, "vm-mailboxfull");
07425 }
07426
07427 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07428 strcpy(textfile, msgfile);
07429 strcpy(backup, msgfile);
07430 strcpy(backup_textfile, msgfile);
07431 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07432 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07433 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07434 if (ast_fileexists(backup, NULL, NULL) > 0) {
07435 ast_filerename(backup, msgfile, NULL);
07436 rename(backup_textfile, textfile);
07437 }
07438 #endif
07439 }
07440 DISPOSE(dir, curmsg);
07441 #ifndef IMAP_STORAGE
07442 if (cmd) {
07443 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07444 strcpy(textfile, msgfile);
07445 strcpy(backup_textfile, msgfile);
07446 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07447 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07448 rename(backup_textfile, textfile);
07449 }
07450 #endif
07451 }
07452
07453
07454 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07455 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07456 free_user(vmtmp);
07457 }
07458 return res ? res : cmd;
07459 }
07460
07461 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07462 {
07463 int res;
07464 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07465 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07466 return res;
07467 }
07468
07469 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07470 {
07471 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
07472 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);
07473 }
07474
07475 static int play_message_category(struct ast_channel *chan, const char *category)
07476 {
07477 int res = 0;
07478
07479 if (!ast_strlen_zero(category))
07480 res = ast_play_and_wait(chan, category);
07481
07482 if (res) {
07483 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07484 res = 0;
07485 }
07486
07487 return res;
07488 }
07489
07490 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07491 {
07492 int res = 0;
07493 struct vm_zone *the_zone = NULL;
07494 time_t t;
07495
07496 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07497 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07498 return 0;
07499 }
07500
07501
07502 if (!ast_strlen_zero(vmu->zonetag)) {
07503
07504 struct vm_zone *z;
07505 AST_LIST_LOCK(&zones);
07506 AST_LIST_TRAVERSE(&zones, z, list) {
07507 if (!strcmp(z->name, vmu->zonetag)) {
07508 the_zone = z;
07509 break;
07510 }
07511 }
07512 AST_LIST_UNLOCK(&zones);
07513 }
07514
07515
07516 #if 0
07517
07518 ast_localtime(&t, &time_now, NULL);
07519 tv_now = ast_tvnow();
07520 ast_localtime(&tv_now, &time_then, NULL);
07521
07522
07523 if (time_now.tm_year == time_then.tm_year)
07524 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07525 else
07526 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07527 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07528
07529
07530 #endif
07531 if (the_zone) {
07532 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07533 } else if (!strncasecmp(chan->language, "de", 2)) {
07534 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07535 } else if (!strncasecmp(chan->language, "gr", 2)) {
07536 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07537 } else if (!strncasecmp(chan->language, "it", 2)) {
07538 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);
07539 } else if (!strncasecmp(chan->language, "nl", 2)) {
07540 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07541 } else if (!strncasecmp(chan->language, "no", 2)) {
07542 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07543 } else if (!strncasecmp(chan->language, "pl", 2)) {
07544 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07545 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07546 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);
07547 } else if (!strncasecmp(chan->language, "se", 2)) {
07548 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07549 } else if (!strncasecmp(chan->language, "zh", 2)) {
07550 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07551 } else if (!strncasecmp(chan->language, "vi", 2)) {
07552 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' A 'digits/day' dB 'digits/year' Y 'digits/at' k 'hours' M 'minutes'", NULL);
07553 } else {
07554 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07555 }
07556 #if 0
07557 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07558 #endif
07559 return res;
07560 }
07561
07562
07563
07564 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07565 {
07566 int res = 0;
07567 int i;
07568 char *callerid, *name;
07569 char prefile[PATH_MAX] = "";
07570
07571
07572
07573
07574
07575
07576
07577
07578
07579 if ((cid == NULL)||(context == NULL))
07580 return res;
07581
07582
07583 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07584 ast_callerid_parse(cid, &name, &callerid);
07585 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07586
07587
07588 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07589 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07590 if ((strcmp(cidinternalcontexts[i], context) == 0))
07591 break;
07592 }
07593 if (i != MAX_NUM_CID_CONTEXTS){
07594 if (!res) {
07595 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07596 if (!ast_strlen_zero(prefile)) {
07597
07598 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07599 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07600 if (!callback)
07601 res = wait_file2(chan, vms, "vm-from");
07602 res = ast_stream_and_wait(chan, prefile, "");
07603 } else {
07604 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07605
07606 if (!callback)
07607 res = wait_file2(chan, vms, "vm-from-extension");
07608 res = ast_say_digit_str(chan, callerid, "", chan->language);
07609 }
07610 }
07611 }
07612 } else if (!res) {
07613 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07614
07615 if (!callback)
07616 res = wait_file2(chan, vms, "vm-from-phonenumber");
07617 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07618 }
07619 } else {
07620
07621 ast_debug(1, "VM-CID: From an unknown number\n");
07622
07623 res = wait_file2(chan, vms, "vm-unknown-caller");
07624 }
07625 return res;
07626 }
07627
07628 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07629 {
07630 int res = 0;
07631 int durationm;
07632 int durations;
07633
07634 if (duration == NULL)
07635 return res;
07636
07637
07638 durations = atoi(duration);
07639 durationm = (durations / 60);
07640
07641 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07642
07643 if ((!res) && (durationm >= minduration)) {
07644 res = wait_file2(chan, vms, "vm-duration");
07645
07646
07647 if (!strncasecmp(chan->language, "pl", 2)) {
07648 div_t num = div(durationm, 10);
07649
07650 if (durationm == 1) {
07651 res = ast_play_and_wait(chan, "digits/1z");
07652 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07653 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07654 if (num.rem == 2) {
07655 if (!num.quot) {
07656 res = ast_play_and_wait(chan, "digits/2-ie");
07657 } else {
07658 res = say_and_wait(chan, durationm - 2 , chan->language);
07659 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07660 }
07661 } else {
07662 res = say_and_wait(chan, durationm, chan->language);
07663 }
07664 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07665 } else {
07666 res = say_and_wait(chan, durationm, chan->language);
07667 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07668 }
07669
07670 } else {
07671 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07672 res = wait_file2(chan, vms, "vm-minutes");
07673 }
07674 }
07675 return res;
07676 }
07677
07678 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07679 {
07680 int res = 0;
07681 char filename[256], *cid;
07682 const char *origtime, *context, *category, *duration, *flag;
07683 struct ast_config *msg_cfg;
07684 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07685
07686 vms->starting = 0;
07687 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07688 adsi_message(chan, vms);
07689 if (!vms->curmsg) {
07690 res = wait_file2(chan, vms, "vm-first");
07691 } else if (vms->curmsg == vms->lastmsg) {
07692 res = wait_file2(chan, vms, "vm-last");
07693 }
07694
07695 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07696 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07697 msg_cfg = ast_config_load(filename, config_flags);
07698 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
07699 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07700 return 0;
07701 }
07702 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07703
07704
07705 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07706 res = wait_file2(chan, vms, "vm-Urgent");
07707 }
07708
07709 if (!res) {
07710
07711
07712 if (!strncasecmp(chan->language, "pl", 2)) {
07713 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07714 int ten, one;
07715 char nextmsg[256];
07716 ten = (vms->curmsg + 1) / 10;
07717 one = (vms->curmsg + 1) % 10;
07718
07719 if (vms->curmsg < 20) {
07720 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07721 res = wait_file2(chan, vms, nextmsg);
07722 } else {
07723 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07724 res = wait_file2(chan, vms, nextmsg);
07725 if (one > 0) {
07726 if (!res) {
07727 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07728 res = wait_file2(chan, vms, nextmsg);
07729 }
07730 }
07731 }
07732 }
07733 if (!res)
07734 res = wait_file2(chan, vms, "vm-message");
07735
07736 } else if (!strncasecmp(chan->language, "he", 2)) {
07737 if (!vms->curmsg) {
07738 res = wait_file2(chan, vms, "vm-message");
07739 res = wait_file2(chan, vms, "vm-first");
07740 } else if (vms->curmsg == vms->lastmsg) {
07741 res = wait_file2(chan, vms, "vm-message");
07742 res = wait_file2(chan, vms, "vm-last");
07743 } else {
07744 res = wait_file2(chan, vms, "vm-message");
07745 res = wait_file2(chan, vms, "vm-number");
07746 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07747 }
07748
07749 } else if (!strncasecmp(chan->language, "vi", 2)) {
07750 if (!vms->curmsg) {
07751 res = wait_file2(chan, vms, "vm-message");
07752 res = wait_file2(chan, vms, "vm-first");
07753 } else if (vms->curmsg == vms->lastmsg) {
07754 res = wait_file2(chan, vms, "vm-message");
07755 res = wait_file2(chan, vms, "vm-last");
07756 } else {
07757 res = wait_file2(chan, vms, "vm-message");
07758 res = wait_file2(chan, vms, "vm-number");
07759 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07760 }
07761 } else {
07762 if (!strncasecmp(chan->language, "se", 2)) {
07763 res = wait_file2(chan, vms, "vm-meddelandet");
07764 } else {
07765 res = wait_file2(chan, vms, "vm-message");
07766 }
07767 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07768 if (!res) {
07769 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
07770 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07771 }
07772 }
07773 }
07774 }
07775
07776 if (!msg_cfg) {
07777 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07778 return 0;
07779 }
07780
07781 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07782 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07783 DISPOSE(vms->curdir, vms->curmsg);
07784 ast_config_destroy(msg_cfg);
07785 return 0;
07786 }
07787
07788 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07789 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07790 category = ast_variable_retrieve(msg_cfg, "message", "category");
07791
07792 context = ast_variable_retrieve(msg_cfg, "message", "context");
07793 if (!strncasecmp("macro", context, 5))
07794 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07795 if (!res) {
07796 res = play_message_category(chan, category);
07797 }
07798 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
07799 res = play_message_datetime(chan, vmu, origtime, filename);
07800 }
07801 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
07802 res = play_message_callerid(chan, vms, cid, context, 0);
07803 }
07804 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
07805 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07806 }
07807
07808 if (res == '1') {
07809 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07810 res = 0;
07811 }
07812 ast_config_destroy(msg_cfg);
07813
07814 if (!res) {
07815 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07816 #ifdef IMAP_STORAGE
07817 ast_mutex_lock(&vms->lock);
07818 #endif
07819 vms->heard[vms->curmsg] = 1;
07820 #ifdef IMAP_STORAGE
07821 ast_mutex_unlock(&vms->lock);
07822
07823
07824
07825 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07826 wait_file(chan, vms, vms->introfn);
07827 }
07828 #endif
07829 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07830 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07831 res = 0;
07832 }
07833 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07834 }
07835 DISPOSE(vms->curdir, vms->curmsg);
07836 return res;
07837 }
07838
07839 #ifdef IMAP_STORAGE
07840 static int imap_remove_file(char *dir, int msgnum)
07841 {
07842 char fn[PATH_MAX];
07843 char full_fn[PATH_MAX];
07844 char intro[PATH_MAX] = {0,};
07845
07846 if (msgnum > -1) {
07847 make_file(fn, sizeof(fn), dir, msgnum);
07848 snprintf(intro, sizeof(intro), "%sintro", fn);
07849 } else
07850 ast_copy_string(fn, dir, sizeof(fn));
07851
07852 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07853 ast_filedelete(fn, NULL);
07854 if (!ast_strlen_zero(intro)) {
07855 ast_filedelete(intro, NULL);
07856 }
07857 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07858 unlink(full_fn);
07859 }
07860 return 0;
07861 }
07862
07863
07864
07865 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07866 {
07867 char *file, *filename;
07868 char *attachment;
07869 char arg[10];
07870 int i;
07871 BODY* body;
07872
07873 file = strrchr(ast_strdupa(dir), '/');
07874 if (file) {
07875 *file++ = '\0';
07876 } else {
07877 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07878 return -1;
07879 }
07880
07881 ast_mutex_lock(&vms->lock);
07882 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07883 mail_fetchstructure(vms->mailstream, i + 1, &body);
07884
07885 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07886 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07887 } else {
07888 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07889 ast_mutex_unlock(&vms->lock);
07890 return -1;
07891 }
07892 filename = strsep(&attachment, ".");
07893 if (!strcmp(filename, file)) {
07894 sprintf(arg, "%d", i + 1);
07895 mail_setflag(vms->mailstream, arg, "\\DELETED");
07896 }
07897 }
07898 mail_expunge(vms->mailstream);
07899 ast_mutex_unlock(&vms->lock);
07900 return 0;
07901 }
07902
07903 #elif !defined(IMAP_STORAGE)
07904 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07905 {
07906 int count_msg, last_msg;
07907
07908 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07909
07910
07911
07912
07913 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07914
07915
07916 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07917
07918
07919 count_msg = count_messages(vmu, vms->curdir);
07920 if (count_msg < 0) {
07921 return count_msg;
07922 } else {
07923 vms->lastmsg = count_msg - 1;
07924 }
07925
07926 if (vm_allocate_dh(vms, vmu, count_msg)) {
07927 return -1;
07928 }
07929
07930
07931
07932
07933
07934
07935
07936
07937 if (vm_lock_path(vms->curdir)) {
07938 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07939 return ERROR_LOCK_PATH;
07940 }
07941
07942
07943 last_msg = last_message_index(vmu, vms->curdir);
07944 ast_unlock_path(vms->curdir);
07945
07946 if (last_msg < -1) {
07947 return last_msg;
07948 } else if (vms->lastmsg != last_msg) {
07949 ast_log(LOG_NOTICE, "Resequencing Mailbox: %s, expected %d but found %d message(s) in box with max threshold of %d.\n", vms->curdir, last_msg + 1, vms->lastmsg + 1, vmu->maxmsg);
07950 resequence_mailbox(vmu, vms->curdir, count_msg);
07951 }
07952
07953 return 0;
07954 }
07955 #endif
07956
07957 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
07958 {
07959 int x = 0;
07960 int last_msg_idx = 0;
07961
07962 #ifndef IMAP_STORAGE
07963 int res = 0, nummsg;
07964 char fn2[PATH_MAX];
07965 #endif
07966
07967 if (vms->lastmsg <= -1) {
07968 goto done;
07969 }
07970
07971 vms->curmsg = -1;
07972 #ifndef IMAP_STORAGE
07973
07974 if (vm_lock_path(vms->curdir)) {
07975 return ERROR_LOCK_PATH;
07976 }
07977
07978
07979 last_msg_idx = last_message_index(vmu, vms->curdir);
07980 if (last_msg_idx != vms->lastmsg) {
07981 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
07982 }
07983
07984
07985 for (x = 0; x < last_msg_idx + 1; x++) {
07986 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
07987
07988 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
07989 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
07990 break;
07991 }
07992 vms->curmsg++;
07993 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
07994 if (strcmp(vms->fn, fn2)) {
07995 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
07996 }
07997 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
07998
07999 res = save_to_folder(vmu, vms, x, 1);
08000 if (res == ERROR_LOCK_PATH) {
08001
08002 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
08003 vms->deleted[x] = 0;
08004 vms->heard[x] = 0;
08005 --x;
08006 }
08007 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
08008
08009 res = save_to_folder(vmu, vms, x, 10);
08010 if (res == ERROR_LOCK_PATH) {
08011
08012 vms->deleted[x] = 0;
08013 vms->heard[x] = 0;
08014 --x;
08015 }
08016 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
08017
08018
08019 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08020 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08021 DELETE(vms->curdir, x, vms->fn, vmu);
08022 }
08023 }
08024 }
08025
08026
08027 nummsg = x - 1;
08028 for (x = vms->curmsg + 1; x <= nummsg; x++) {
08029 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08030 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08031 DELETE(vms->curdir, x, vms->fn, vmu);
08032 }
08033 }
08034 ast_unlock_path(vms->curdir);
08035 #else
08036 ast_mutex_lock(&vms->lock);
08037 if (vms->deleted) {
08038
08039
08040 last_msg_idx = vms->dh_arraysize;
08041 for (x = last_msg_idx - 1; x >= 0; x--) {
08042 if (vms->deleted[x]) {
08043 ast_debug(3, "IMAP delete of %d\n", x);
08044 DELETE(vms->curdir, x, vms->fn, vmu);
08045 }
08046 }
08047 }
08048 #endif
08049
08050 done:
08051 if (vms->deleted) {
08052 ast_free(vms->deleted);
08053 vms->deleted = NULL;
08054 }
08055 if (vms->heard) {
08056 ast_free(vms->heard);
08057 vms->heard = NULL;
08058 }
08059 vms->dh_arraysize = 0;
08060 #ifdef IMAP_STORAGE
08061 ast_mutex_unlock(&vms->lock);
08062 #endif
08063
08064 return 0;
08065 }
08066
08067
08068
08069
08070
08071
08072
08073 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08074 {
08075 int cmd;
08076 char *buf;
08077
08078 buf = alloca(strlen(box) + 2);
08079 strcpy(buf, box);
08080 strcat(buf, "s");
08081
08082 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08083 cmd = ast_play_and_wait(chan, buf);
08084 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08085 } else {
08086 cmd = ast_play_and_wait(chan, "vm-messages");
08087 return cmd ? cmd : ast_play_and_wait(chan, box);
08088 }
08089 }
08090
08091 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08092 {
08093 int cmd;
08094
08095 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08096 if (!strcasecmp(box, "vm-INBOX"))
08097 cmd = ast_play_and_wait(chan, "vm-new-e");
08098 else
08099 cmd = ast_play_and_wait(chan, "vm-old-e");
08100 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08101 } else {
08102 cmd = ast_play_and_wait(chan, "vm-messages");
08103 return cmd ? cmd : ast_play_and_wait(chan, box);
08104 }
08105 }
08106
08107 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08108 {
08109 int cmd;
08110
08111 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08112 cmd = ast_play_and_wait(chan, "vm-messages");
08113 return cmd ? cmd : ast_play_and_wait(chan, box);
08114 } else {
08115 cmd = ast_play_and_wait(chan, box);
08116 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08117 }
08118 }
08119
08120 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08121 {
08122 int cmd;
08123
08124 if ( !strncasecmp(chan->language, "it", 2) ||
08125 !strncasecmp(chan->language, "es", 2) ||
08126 !strncasecmp(chan->language, "pt", 2)) {
08127 cmd = ast_play_and_wait(chan, "vm-messages");
08128 return cmd ? cmd : ast_play_and_wait(chan, box);
08129 } else if (!strncasecmp(chan->language, "gr", 2)) {
08130 return vm_play_folder_name_gr(chan, box);
08131 } else if (!strncasecmp(chan->language, "he", 2)) {
08132 return ast_play_and_wait(chan, box);
08133 } else if (!strncasecmp(chan->language, "pl", 2)) {
08134 return vm_play_folder_name_pl(chan, box);
08135 } else if (!strncasecmp(chan->language, "ua", 2)) {
08136 return vm_play_folder_name_ua(chan, box);
08137 } else if (!strncasecmp(chan->language, "vi", 2)) {
08138 return ast_play_and_wait(chan, box);
08139 } else {
08140 cmd = ast_play_and_wait(chan, box);
08141 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08142 }
08143 }
08144
08145
08146
08147
08148
08149
08150
08151
08152
08153
08154
08155
08156
08157 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08158 {
08159 int res = 0;
08160
08161 if (vms->newmessages) {
08162 res = ast_play_and_wait(chan, "vm-youhave");
08163 if (!res)
08164 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
08165 if (!res) {
08166 if ((vms->newmessages == 1)) {
08167 res = ast_play_and_wait(chan, "vm-INBOX");
08168 if (!res)
08169 res = ast_play_and_wait(chan, "vm-message");
08170 } else {
08171 res = ast_play_and_wait(chan, "vm-INBOXs");
08172 if (!res)
08173 res = ast_play_and_wait(chan, "vm-messages");
08174 }
08175 }
08176 } else if (vms->oldmessages){
08177 res = ast_play_and_wait(chan, "vm-youhave");
08178 if (!res)
08179 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
08180 if ((vms->oldmessages == 1)){
08181 res = ast_play_and_wait(chan, "vm-Old");
08182 if (!res)
08183 res = ast_play_and_wait(chan, "vm-message");
08184 } else {
08185 res = ast_play_and_wait(chan, "vm-Olds");
08186 if (!res)
08187 res = ast_play_and_wait(chan, "vm-messages");
08188 }
08189 } else if (!vms->oldmessages && !vms->newmessages)
08190 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08191 return res;
08192 }
08193
08194
08195
08196
08197
08198
08199
08200
08201
08202
08203
08204
08205
08206
08207
08208
08209
08210
08211
08212
08213
08214
08215
08216
08217
08218
08219
08220
08221
08222
08223
08224
08225
08226
08227
08228
08229
08230
08231
08232
08233
08234
08235
08236
08237
08238
08239
08240
08241
08242
08243
08244
08245
08246
08247
08248
08249
08250
08251 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08252 {
08253 int res;
08254 int lastnum = 0;
08255
08256 res = ast_play_and_wait(chan, "vm-youhave");
08257
08258 if (!res && vms->newmessages) {
08259 lastnum = vms->newmessages;
08260
08261 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08262 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08263 }
08264
08265 if (!res && vms->oldmessages) {
08266 res = ast_play_and_wait(chan, "vm-and");
08267 }
08268 }
08269
08270 if (!res && vms->oldmessages) {
08271 lastnum = vms->oldmessages;
08272
08273 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08274 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08275 }
08276 }
08277
08278 if (!res) {
08279 if (lastnum == 0) {
08280 res = ast_play_and_wait(chan, "vm-no");
08281 }
08282 if (!res) {
08283 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08284 }
08285 }
08286
08287 return res;
08288 }
08289
08290
08291 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08292 {
08293 int res = 0;
08294
08295
08296 if (!res) {
08297 if ((vms->newmessages) || (vms->oldmessages)) {
08298 res = ast_play_and_wait(chan, "vm-youhave");
08299 }
08300
08301
08302
08303
08304
08305 if (vms->newmessages) {
08306 if (!res) {
08307 if (vms->newmessages == 1) {
08308 res = ast_play_and_wait(chan, "vm-INBOX1");
08309 } else {
08310 if (vms->newmessages == 2) {
08311 res = ast_play_and_wait(chan, "vm-shtei");
08312 } else {
08313 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08314 }
08315 res = ast_play_and_wait(chan, "vm-INBOX");
08316 }
08317 }
08318 if (vms->oldmessages && !res) {
08319 res = ast_play_and_wait(chan, "vm-and");
08320 if (vms->oldmessages == 1) {
08321 res = ast_play_and_wait(chan, "vm-Old1");
08322 } else {
08323 if (vms->oldmessages == 2) {
08324 res = ast_play_and_wait(chan, "vm-shtei");
08325 } else {
08326 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08327 }
08328 res = ast_play_and_wait(chan, "vm-Old");
08329 }
08330 }
08331 }
08332 if (!res && vms->oldmessages && !vms->newmessages) {
08333 if (!res) {
08334 if (vms->oldmessages == 1) {
08335 res = ast_play_and_wait(chan, "vm-Old1");
08336 } else {
08337 if (vms->oldmessages == 2) {
08338 res = ast_play_and_wait(chan, "vm-shtei");
08339 } else {
08340 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08341 }
08342 res = ast_play_and_wait(chan, "vm-Old");
08343 }
08344 }
08345 }
08346 if (!res) {
08347 if (!vms->oldmessages && !vms->newmessages) {
08348 if (!res) {
08349 res = ast_play_and_wait(chan, "vm-nomessages");
08350 }
08351 }
08352 }
08353 }
08354 return res;
08355 }
08356
08357
08358 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08359 {
08360 int res;
08361
08362
08363 res = ast_play_and_wait(chan, "vm-youhave");
08364 if (!res) {
08365 if (vms->urgentmessages) {
08366 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08367 if (!res)
08368 res = ast_play_and_wait(chan, "vm-Urgent");
08369 if ((vms->oldmessages || vms->newmessages) && !res) {
08370 res = ast_play_and_wait(chan, "vm-and");
08371 } else if (!res) {
08372 if ((vms->urgentmessages == 1))
08373 res = ast_play_and_wait(chan, "vm-message");
08374 else
08375 res = ast_play_and_wait(chan, "vm-messages");
08376 }
08377 }
08378 if (vms->newmessages) {
08379 res = say_and_wait(chan, vms->newmessages, chan->language);
08380 if (!res)
08381 res = ast_play_and_wait(chan, "vm-INBOX");
08382 if (vms->oldmessages && !res)
08383 res = ast_play_and_wait(chan, "vm-and");
08384 else if (!res) {
08385 if ((vms->newmessages == 1))
08386 res = ast_play_and_wait(chan, "vm-message");
08387 else
08388 res = ast_play_and_wait(chan, "vm-messages");
08389 }
08390
08391 }
08392 if (!res && vms->oldmessages) {
08393 res = say_and_wait(chan, vms->oldmessages, chan->language);
08394 if (!res)
08395 res = ast_play_and_wait(chan, "vm-Old");
08396 if (!res) {
08397 if (vms->oldmessages == 1)
08398 res = ast_play_and_wait(chan, "vm-message");
08399 else
08400 res = ast_play_and_wait(chan, "vm-messages");
08401 }
08402 }
08403 if (!res) {
08404 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08405 res = ast_play_and_wait(chan, "vm-no");
08406 if (!res)
08407 res = ast_play_and_wait(chan, "vm-messages");
08408 }
08409 }
08410 }
08411 return res;
08412 }
08413
08414
08415 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08416 {
08417
08418 int res;
08419 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08420 res = ast_play_and_wait(chan, "vm-no") ||
08421 ast_play_and_wait(chan, "vm-message");
08422 else
08423 res = ast_play_and_wait(chan, "vm-youhave");
08424 if (!res && vms->newmessages) {
08425 res = (vms->newmessages == 1) ?
08426 ast_play_and_wait(chan, "digits/un") ||
08427 ast_play_and_wait(chan, "vm-nuovo") ||
08428 ast_play_and_wait(chan, "vm-message") :
08429
08430 say_and_wait(chan, vms->newmessages, chan->language) ||
08431 ast_play_and_wait(chan, "vm-nuovi") ||
08432 ast_play_and_wait(chan, "vm-messages");
08433 if (!res && vms->oldmessages)
08434 res = ast_play_and_wait(chan, "vm-and");
08435 }
08436 if (!res && vms->oldmessages) {
08437 res = (vms->oldmessages == 1) ?
08438 ast_play_and_wait(chan, "digits/un") ||
08439 ast_play_and_wait(chan, "vm-vecchio") ||
08440 ast_play_and_wait(chan, "vm-message") :
08441
08442 say_and_wait(chan, vms->oldmessages, chan->language) ||
08443 ast_play_and_wait(chan, "vm-vecchi") ||
08444 ast_play_and_wait(chan, "vm-messages");
08445 }
08446 return res;
08447 }
08448
08449
08450 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08451 {
08452
08453 int res;
08454 div_t num;
08455
08456 if (!vms->oldmessages && !vms->newmessages) {
08457 res = ast_play_and_wait(chan, "vm-no");
08458 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08459 return res;
08460 } else {
08461 res = ast_play_and_wait(chan, "vm-youhave");
08462 }
08463
08464 if (vms->newmessages) {
08465 num = div(vms->newmessages, 10);
08466 if (vms->newmessages == 1) {
08467 res = ast_play_and_wait(chan, "digits/1-a");
08468 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08469 res = res ? res : ast_play_and_wait(chan, "vm-message");
08470 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08471 if (num.rem == 2) {
08472 if (!num.quot) {
08473 res = ast_play_and_wait(chan, "digits/2-ie");
08474 } else {
08475 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08476 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08477 }
08478 } else {
08479 res = say_and_wait(chan, vms->newmessages, chan->language);
08480 }
08481 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08482 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08483 } else {
08484 res = say_and_wait(chan, vms->newmessages, chan->language);
08485 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08486 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08487 }
08488 if (!res && vms->oldmessages)
08489 res = ast_play_and_wait(chan, "vm-and");
08490 }
08491 if (!res && vms->oldmessages) {
08492 num = div(vms->oldmessages, 10);
08493 if (vms->oldmessages == 1) {
08494 res = ast_play_and_wait(chan, "digits/1-a");
08495 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08496 res = res ? res : ast_play_and_wait(chan, "vm-message");
08497 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08498 if (num.rem == 2) {
08499 if (!num.quot) {
08500 res = ast_play_and_wait(chan, "digits/2-ie");
08501 } else {
08502 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08503 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08504 }
08505 } else {
08506 res = say_and_wait(chan, vms->oldmessages, chan->language);
08507 }
08508 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08509 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08510 } else {
08511 res = say_and_wait(chan, vms->oldmessages, chan->language);
08512 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08513 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08514 }
08515 }
08516
08517 return res;
08518 }
08519
08520
08521 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08522 {
08523
08524 int res;
08525
08526 res = ast_play_and_wait(chan, "vm-youhave");
08527 if (res)
08528 return res;
08529
08530 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08531 res = ast_play_and_wait(chan, "vm-no");
08532 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08533 return res;
08534 }
08535
08536 if (vms->newmessages) {
08537 if ((vms->newmessages == 1)) {
08538 res = ast_play_and_wait(chan, "digits/ett");
08539 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08540 res = res ? res : ast_play_and_wait(chan, "vm-message");
08541 } else {
08542 res = say_and_wait(chan, vms->newmessages, chan->language);
08543 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08544 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08545 }
08546 if (!res && vms->oldmessages)
08547 res = ast_play_and_wait(chan, "vm-and");
08548 }
08549 if (!res && vms->oldmessages) {
08550 if (vms->oldmessages == 1) {
08551 res = ast_play_and_wait(chan, "digits/ett");
08552 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08553 res = res ? res : ast_play_and_wait(chan, "vm-message");
08554 } else {
08555 res = say_and_wait(chan, vms->oldmessages, chan->language);
08556 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08557 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08558 }
08559 }
08560
08561 return res;
08562 }
08563
08564
08565 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08566 {
08567
08568 int res;
08569
08570 res = ast_play_and_wait(chan, "vm-youhave");
08571 if (res)
08572 return res;
08573
08574 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08575 res = ast_play_and_wait(chan, "vm-no");
08576 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08577 return res;
08578 }
08579
08580 if (vms->newmessages) {
08581 if ((vms->newmessages == 1)) {
08582 res = ast_play_and_wait(chan, "digits/1");
08583 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08584 res = res ? res : ast_play_and_wait(chan, "vm-message");
08585 } else {
08586 res = say_and_wait(chan, vms->newmessages, chan->language);
08587 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08588 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08589 }
08590 if (!res && vms->oldmessages)
08591 res = ast_play_and_wait(chan, "vm-and");
08592 }
08593 if (!res && vms->oldmessages) {
08594 if (vms->oldmessages == 1) {
08595 res = ast_play_and_wait(chan, "digits/1");
08596 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08597 res = res ? res : ast_play_and_wait(chan, "vm-message");
08598 } else {
08599 res = say_and_wait(chan, vms->oldmessages, chan->language);
08600 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08601 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08602 }
08603 }
08604
08605 return res;
08606 }
08607
08608
08609 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08610 {
08611
08612 int res;
08613 res = ast_play_and_wait(chan, "vm-youhave");
08614 if (!res) {
08615 if (vms->newmessages) {
08616 if ((vms->newmessages == 1))
08617 res = ast_play_and_wait(chan, "digits/1F");
08618 else
08619 res = say_and_wait(chan, vms->newmessages, chan->language);
08620 if (!res)
08621 res = ast_play_and_wait(chan, "vm-INBOX");
08622 if (vms->oldmessages && !res)
08623 res = ast_play_and_wait(chan, "vm-and");
08624 else if (!res) {
08625 if ((vms->newmessages == 1))
08626 res = ast_play_and_wait(chan, "vm-message");
08627 else
08628 res = ast_play_and_wait(chan, "vm-messages");
08629 }
08630
08631 }
08632 if (!res && vms->oldmessages) {
08633 if (vms->oldmessages == 1)
08634 res = ast_play_and_wait(chan, "digits/1F");
08635 else
08636 res = say_and_wait(chan, vms->oldmessages, chan->language);
08637 if (!res)
08638 res = ast_play_and_wait(chan, "vm-Old");
08639 if (!res) {
08640 if (vms->oldmessages == 1)
08641 res = ast_play_and_wait(chan, "vm-message");
08642 else
08643 res = ast_play_and_wait(chan, "vm-messages");
08644 }
08645 }
08646 if (!res) {
08647 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08648 res = ast_play_and_wait(chan, "vm-no");
08649 if (!res)
08650 res = ast_play_and_wait(chan, "vm-messages");
08651 }
08652 }
08653 }
08654 return res;
08655 }
08656
08657
08658 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08659 {
08660
08661 int res;
08662 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08663 res = ast_play_and_wait(chan, "vm-youhaveno");
08664 if (!res)
08665 res = ast_play_and_wait(chan, "vm-messages");
08666 } else {
08667 res = ast_play_and_wait(chan, "vm-youhave");
08668 }
08669 if (!res) {
08670 if (vms->newmessages) {
08671 if (!res) {
08672 if ((vms->newmessages == 1)) {
08673 res = ast_play_and_wait(chan, "digits/1M");
08674 if (!res)
08675 res = ast_play_and_wait(chan, "vm-message");
08676 if (!res)
08677 res = ast_play_and_wait(chan, "vm-INBOXs");
08678 } else {
08679 res = say_and_wait(chan, vms->newmessages, chan->language);
08680 if (!res)
08681 res = ast_play_and_wait(chan, "vm-messages");
08682 if (!res)
08683 res = ast_play_and_wait(chan, "vm-INBOX");
08684 }
08685 }
08686 if (vms->oldmessages && !res)
08687 res = ast_play_and_wait(chan, "vm-and");
08688 }
08689 if (vms->oldmessages) {
08690 if (!res) {
08691 if (vms->oldmessages == 1) {
08692 res = ast_play_and_wait(chan, "digits/1M");
08693 if (!res)
08694 res = ast_play_and_wait(chan, "vm-message");
08695 if (!res)
08696 res = ast_play_and_wait(chan, "vm-Olds");
08697 } else {
08698 res = say_and_wait(chan, vms->oldmessages, chan->language);
08699 if (!res)
08700 res = ast_play_and_wait(chan, "vm-messages");
08701 if (!res)
08702 res = ast_play_and_wait(chan, "vm-Old");
08703 }
08704 }
08705 }
08706 }
08707 return res;
08708 }
08709
08710
08711 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08712
08713 int res;
08714 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08715 res = ast_play_and_wait(chan, "vm-nomessages");
08716 return res;
08717 } else {
08718 res = ast_play_and_wait(chan, "vm-youhave");
08719 }
08720 if (vms->newmessages) {
08721 if (!res)
08722 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08723 if ((vms->newmessages == 1)) {
08724 if (!res)
08725 res = ast_play_and_wait(chan, "vm-message");
08726 if (!res)
08727 res = ast_play_and_wait(chan, "vm-INBOXs");
08728 } else {
08729 if (!res)
08730 res = ast_play_and_wait(chan, "vm-messages");
08731 if (!res)
08732 res = ast_play_and_wait(chan, "vm-INBOX");
08733 }
08734 if (vms->oldmessages && !res)
08735 res = ast_play_and_wait(chan, "vm-and");
08736 }
08737 if (vms->oldmessages) {
08738 if (!res)
08739 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08740 if (vms->oldmessages == 1) {
08741 if (!res)
08742 res = ast_play_and_wait(chan, "vm-message");
08743 if (!res)
08744 res = ast_play_and_wait(chan, "vm-Olds");
08745 } else {
08746 if (!res)
08747 res = ast_play_and_wait(chan, "vm-messages");
08748 if (!res)
08749 res = ast_play_and_wait(chan, "vm-Old");
08750 }
08751 }
08752 return res;
08753 }
08754
08755
08756 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08757 {
08758
08759 int res;
08760 res = ast_play_and_wait(chan, "vm-youhave");
08761 if (!res) {
08762 if (vms->newmessages) {
08763 res = say_and_wait(chan, vms->newmessages, chan->language);
08764 if (!res)
08765 res = ast_play_and_wait(chan, "vm-INBOX");
08766 if (vms->oldmessages && !res)
08767 res = ast_play_and_wait(chan, "vm-and");
08768 else if (!res) {
08769 if ((vms->newmessages == 1))
08770 res = ast_play_and_wait(chan, "vm-message");
08771 else
08772 res = ast_play_and_wait(chan, "vm-messages");
08773 }
08774
08775 }
08776 if (!res && vms->oldmessages) {
08777 res = say_and_wait(chan, vms->oldmessages, chan->language);
08778 if (!res)
08779 res = ast_play_and_wait(chan, "vm-Old");
08780 if (!res) {
08781 if (vms->oldmessages == 1)
08782 res = ast_play_and_wait(chan, "vm-message");
08783 else
08784 res = ast_play_and_wait(chan, "vm-messages");
08785 }
08786 }
08787 if (!res) {
08788 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08789 res = ast_play_and_wait(chan, "vm-no");
08790 if (!res)
08791 res = ast_play_and_wait(chan, "vm-messages");
08792 }
08793 }
08794 }
08795 return res;
08796 }
08797
08798
08799 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08800 {
08801
08802 int res;
08803 res = ast_play_and_wait(chan, "vm-youhave");
08804 if (!res) {
08805 if (vms->newmessages) {
08806 res = say_and_wait(chan, vms->newmessages, chan->language);
08807 if (!res) {
08808 if (vms->newmessages == 1)
08809 res = ast_play_and_wait(chan, "vm-INBOXs");
08810 else
08811 res = ast_play_and_wait(chan, "vm-INBOX");
08812 }
08813 if (vms->oldmessages && !res)
08814 res = ast_play_and_wait(chan, "vm-and");
08815 else if (!res) {
08816 if ((vms->newmessages == 1))
08817 res = ast_play_and_wait(chan, "vm-message");
08818 else
08819 res = ast_play_and_wait(chan, "vm-messages");
08820 }
08821
08822 }
08823 if (!res && vms->oldmessages) {
08824 res = say_and_wait(chan, vms->oldmessages, chan->language);
08825 if (!res) {
08826 if (vms->oldmessages == 1)
08827 res = ast_play_and_wait(chan, "vm-Olds");
08828 else
08829 res = ast_play_and_wait(chan, "vm-Old");
08830 }
08831 if (!res) {
08832 if (vms->oldmessages == 1)
08833 res = ast_play_and_wait(chan, "vm-message");
08834 else
08835 res = ast_play_and_wait(chan, "vm-messages");
08836 }
08837 }
08838 if (!res) {
08839 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08840 res = ast_play_and_wait(chan, "vm-no");
08841 if (!res)
08842 res = ast_play_and_wait(chan, "vm-messages");
08843 }
08844 }
08845 }
08846 return res;
08847 }
08848
08849
08850 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08851 {
08852
08853 int res;
08854 res = ast_play_and_wait(chan, "vm-youhave");
08855 if (!res) {
08856 if (vms->newmessages) {
08857 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08858 if (!res) {
08859 if ((vms->newmessages == 1)) {
08860 res = ast_play_and_wait(chan, "vm-message");
08861 if (!res)
08862 res = ast_play_and_wait(chan, "vm-INBOXs");
08863 } else {
08864 res = ast_play_and_wait(chan, "vm-messages");
08865 if (!res)
08866 res = ast_play_and_wait(chan, "vm-INBOX");
08867 }
08868 }
08869 if (vms->oldmessages && !res)
08870 res = ast_play_and_wait(chan, "vm-and");
08871 }
08872 if (!res && vms->oldmessages) {
08873 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08874 if (!res) {
08875 if (vms->oldmessages == 1) {
08876 res = ast_play_and_wait(chan, "vm-message");
08877 if (!res)
08878 res = ast_play_and_wait(chan, "vm-Olds");
08879 } else {
08880 res = ast_play_and_wait(chan, "vm-messages");
08881 if (!res)
08882 res = ast_play_and_wait(chan, "vm-Old");
08883 }
08884 }
08885 }
08886 if (!res) {
08887 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08888 res = ast_play_and_wait(chan, "vm-no");
08889 if (!res)
08890 res = ast_play_and_wait(chan, "vm-messages");
08891 }
08892 }
08893 }
08894 return res;
08895 }
08896
08897
08898
08899
08900
08901
08902
08903
08904
08905
08906
08907
08908
08909
08910
08911
08912
08913 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08914 {
08915 int res;
08916 res = ast_play_and_wait(chan, "vm-youhave");
08917 if (!res) {
08918 if (vms->newmessages) {
08919 if (vms->newmessages == 1) {
08920 res = ast_play_and_wait(chan, "digits/jednu");
08921 } else {
08922 res = say_and_wait(chan, vms->newmessages, chan->language);
08923 }
08924 if (!res) {
08925 if ((vms->newmessages == 1))
08926 res = ast_play_and_wait(chan, "vm-novou");
08927 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08928 res = ast_play_and_wait(chan, "vm-nove");
08929 if (vms->newmessages > 4)
08930 res = ast_play_and_wait(chan, "vm-novych");
08931 }
08932 if (vms->oldmessages && !res)
08933 res = ast_play_and_wait(chan, "vm-and");
08934 else if (!res) {
08935 if ((vms->newmessages == 1))
08936 res = ast_play_and_wait(chan, "vm-zpravu");
08937 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08938 res = ast_play_and_wait(chan, "vm-zpravy");
08939 if (vms->newmessages > 4)
08940 res = ast_play_and_wait(chan, "vm-zprav");
08941 }
08942 }
08943 if (!res && vms->oldmessages) {
08944 res = say_and_wait(chan, vms->oldmessages, chan->language);
08945 if (!res) {
08946 if ((vms->oldmessages == 1))
08947 res = ast_play_and_wait(chan, "vm-starou");
08948 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08949 res = ast_play_and_wait(chan, "vm-stare");
08950 if (vms->oldmessages > 4)
08951 res = ast_play_and_wait(chan, "vm-starych");
08952 }
08953 if (!res) {
08954 if ((vms->oldmessages == 1))
08955 res = ast_play_and_wait(chan, "vm-zpravu");
08956 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08957 res = ast_play_and_wait(chan, "vm-zpravy");
08958 if (vms->oldmessages > 4)
08959 res = ast_play_and_wait(chan, "vm-zprav");
08960 }
08961 }
08962 if (!res) {
08963 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08964 res = ast_play_and_wait(chan, "vm-no");
08965 if (!res)
08966 res = ast_play_and_wait(chan, "vm-zpravy");
08967 }
08968 }
08969 }
08970 return res;
08971 }
08972
08973
08974 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
08975 {
08976 int res;
08977
08978 res = ast_play_and_wait(chan, "vm-you");
08979
08980 if (!res && vms->newmessages) {
08981 res = ast_play_and_wait(chan, "vm-have");
08982 if (!res)
08983 res = say_and_wait(chan, vms->newmessages, chan->language);
08984 if (!res)
08985 res = ast_play_and_wait(chan, "vm-tong");
08986 if (!res)
08987 res = ast_play_and_wait(chan, "vm-INBOX");
08988 if (vms->oldmessages && !res)
08989 res = ast_play_and_wait(chan, "vm-and");
08990 else if (!res)
08991 res = ast_play_and_wait(chan, "vm-messages");
08992 }
08993 if (!res && vms->oldmessages) {
08994 res = ast_play_and_wait(chan, "vm-have");
08995 if (!res)
08996 res = say_and_wait(chan, vms->oldmessages, chan->language);
08997 if (!res)
08998 res = ast_play_and_wait(chan, "vm-tong");
08999 if (!res)
09000 res = ast_play_and_wait(chan, "vm-Old");
09001 if (!res)
09002 res = ast_play_and_wait(chan, "vm-messages");
09003 }
09004 if (!res && !vms->oldmessages && !vms->newmessages) {
09005 res = ast_play_and_wait(chan, "vm-haveno");
09006 if (!res)
09007 res = ast_play_and_wait(chan, "vm-messages");
09008 }
09009 return res;
09010 }
09011
09012
09013 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
09014 {
09015 int res;
09016
09017
09018 res = ast_play_and_wait(chan, "vm-youhave");
09019 if (!res) {
09020 if (vms->newmessages) {
09021 res = say_and_wait(chan, vms->newmessages, chan->language);
09022 if (!res)
09023 res = ast_play_and_wait(chan, "vm-INBOX");
09024 if (vms->oldmessages && !res)
09025 res = ast_play_and_wait(chan, "vm-and");
09026 }
09027 if (!res && vms->oldmessages) {
09028 res = say_and_wait(chan, vms->oldmessages, chan->language);
09029 if (!res)
09030 res = ast_play_and_wait(chan, "vm-Old");
09031 }
09032 if (!res) {
09033 if (!vms->oldmessages && !vms->newmessages) {
09034 res = ast_play_and_wait(chan, "vm-no");
09035 if (!res)
09036 res = ast_play_and_wait(chan, "vm-message");
09037 }
09038 }
09039 }
09040 return res;
09041 }
09042
09043 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
09044 {
09045 char prefile[256];
09046
09047
09048 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09049 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
09050 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09051 if (ast_fileexists(prefile, NULL, NULL) > 0) {
09052 ast_play_and_wait(chan, "vm-tempgreetactive");
09053 }
09054 DISPOSE(prefile, -1);
09055 }
09056
09057
09058 if (0) {
09059 return 0;
09060 } else if (!strncasecmp(chan->language, "cs", 2)) {
09061 return vm_intro_cs(chan, vms);
09062 } else if (!strncasecmp(chan->language, "cz", 2)) {
09063 static int deprecation_warning = 0;
09064 if (deprecation_warning++ % 10 == 0) {
09065 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09066 }
09067 return vm_intro_cs(chan, vms);
09068 } else if (!strncasecmp(chan->language, "de", 2)) {
09069 return vm_intro_de(chan, vms);
09070 } else if (!strncasecmp(chan->language, "es", 2)) {
09071 return vm_intro_es(chan, vms);
09072 } else if (!strncasecmp(chan->language, "fr", 2)) {
09073 return vm_intro_fr(chan, vms);
09074 } else if (!strncasecmp(chan->language, "gr", 2)) {
09075 return vm_intro_gr(chan, vms);
09076 } else if (!strncasecmp(chan->language, "he", 2)) {
09077 return vm_intro_he(chan, vms);
09078 } else if (!strncasecmp(chan->language, "it", 2)) {
09079 return vm_intro_it(chan, vms);
09080 } else if (!strncasecmp(chan->language, "nl", 2)) {
09081 return vm_intro_nl(chan, vms);
09082 } else if (!strncasecmp(chan->language, "no", 2)) {
09083 return vm_intro_no(chan, vms);
09084 } else if (!strncasecmp(chan->language, "pl", 2)) {
09085 return vm_intro_pl(chan, vms);
09086 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
09087 return vm_intro_pt_BR(chan, vms);
09088 } else if (!strncasecmp(chan->language, "pt", 2)) {
09089 return vm_intro_pt(chan, vms);
09090 } else if (!strncasecmp(chan->language, "ru", 2)) {
09091 return vm_intro_multilang(chan, vms, "n");
09092 } else if (!strncasecmp(chan->language, "se", 2)) {
09093 return vm_intro_se(chan, vms);
09094 } else if (!strncasecmp(chan->language, "ua", 2)) {
09095 return vm_intro_multilang(chan, vms, "n");
09096 } else if (!strncasecmp(chan->language, "vi", 2)) {
09097 return vm_intro_vi(chan, vms);
09098 } else if (!strncasecmp(chan->language, "zh", 2)) {
09099 return vm_intro_zh(chan, vms);
09100 } else {
09101 return vm_intro_en(chan, vms);
09102 }
09103 }
09104
09105 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09106 {
09107 int res = 0;
09108
09109 while (!res) {
09110 if (vms->starting) {
09111 if (vms->lastmsg > -1) {
09112 if (skipadvanced)
09113 res = ast_play_and_wait(chan, "vm-onefor-full");
09114 else
09115 res = ast_play_and_wait(chan, "vm-onefor");
09116 if (!res)
09117 res = vm_play_folder_name(chan, vms->vmbox);
09118 }
09119 if (!res) {
09120 if (skipadvanced)
09121 res = ast_play_and_wait(chan, "vm-opts-full");
09122 else
09123 res = ast_play_and_wait(chan, "vm-opts");
09124 }
09125 } else {
09126
09127 if (skipadvanced) {
09128 res = ast_play_and_wait(chan, "vm-onefor-full");
09129 if (!res)
09130 res = vm_play_folder_name(chan, vms->vmbox);
09131 res = ast_play_and_wait(chan, "vm-opts-full");
09132 }
09133
09134
09135
09136
09137
09138
09139 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09140 res = ast_play_and_wait(chan, "vm-prev");
09141 }
09142 if (!res && !skipadvanced)
09143 res = ast_play_and_wait(chan, "vm-advopts");
09144 if (!res)
09145 res = ast_play_and_wait(chan, "vm-repeat");
09146
09147
09148
09149
09150
09151
09152 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09153 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09154 res = ast_play_and_wait(chan, "vm-next");
09155 }
09156 if (!res) {
09157 int curmsg_deleted;
09158 #ifdef IMAP_STORAGE
09159 ast_mutex_lock(&vms->lock);
09160 #endif
09161 curmsg_deleted = vms->deleted[vms->curmsg];
09162 #ifdef IMAP_STORAGE
09163 ast_mutex_unlock(&vms->lock);
09164 #endif
09165 if (!curmsg_deleted) {
09166 res = ast_play_and_wait(chan, "vm-delete");
09167 } else {
09168 res = ast_play_and_wait(chan, "vm-undelete");
09169 }
09170 if (!res) {
09171 res = ast_play_and_wait(chan, "vm-toforward");
09172 }
09173 if (!res) {
09174 res = ast_play_and_wait(chan, "vm-savemessage");
09175 }
09176 }
09177 }
09178 if (!res) {
09179 res = ast_play_and_wait(chan, "vm-helpexit");
09180 }
09181 if (!res)
09182 res = ast_waitfordigit(chan, 6000);
09183 if (!res) {
09184 vms->repeats++;
09185 if (vms->repeats > 2) {
09186 res = 't';
09187 }
09188 }
09189 }
09190 return res;
09191 }
09192
09193 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09194 {
09195 int res = 0;
09196
09197 while (!res) {
09198 if (vms->lastmsg > -1) {
09199 res = ast_play_and_wait(chan, "vm-listen");
09200 if (!res)
09201 res = vm_play_folder_name(chan, vms->vmbox);
09202 if (!res)
09203 res = ast_play_and_wait(chan, "press");
09204 if (!res)
09205 res = ast_play_and_wait(chan, "digits/1");
09206 }
09207 if (!res)
09208 res = ast_play_and_wait(chan, "vm-opts");
09209 if (!res) {
09210 vms->starting = 0;
09211 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09212 }
09213 }
09214 return res;
09215 }
09216
09217 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09218 {
09219 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
09220 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09221 } else {
09222 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09223 }
09224 }
09225
09226
09227 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09228 {
09229 int cmd = 0;
09230 int duration = 0;
09231 int tries = 0;
09232 char newpassword[80] = "";
09233 char newpassword2[80] = "";
09234 char prefile[PATH_MAX] = "";
09235 unsigned char buf[256];
09236 int bytes = 0;
09237
09238 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09239 if (ast_adsi_available(chan)) {
09240 bytes += adsi_logo(buf + bytes);
09241 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09242 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09243 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09244 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09245 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09246 }
09247
09248
09249 if (ast_test_flag(vmu, VM_FORCENAME)) {
09250 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09251 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09252 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09253 if (cmd < 0 || cmd == 't' || cmd == '#')
09254 return cmd;
09255 }
09256 }
09257
09258
09259 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09260 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09261 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09262 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09263 if (cmd < 0 || cmd == 't' || cmd == '#')
09264 return cmd;
09265 }
09266
09267 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09268 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09269 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09270 if (cmd < 0 || cmd == 't' || cmd == '#')
09271 return cmd;
09272 }
09273 }
09274
09275
09276
09277
09278
09279 for (;;) {
09280 newpassword[1] = '\0';
09281 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09282 if (cmd == '#')
09283 newpassword[0] = '\0';
09284 if (cmd < 0 || cmd == 't' || cmd == '#')
09285 return cmd;
09286 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09287 if (cmd < 0 || cmd == 't' || cmd == '#')
09288 return cmd;
09289 cmd = check_password(vmu, newpassword);
09290 if (cmd != 0) {
09291 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09292 cmd = ast_play_and_wait(chan, vm_invalid_password);
09293 } else {
09294 newpassword2[1] = '\0';
09295 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09296 if (cmd == '#')
09297 newpassword2[0] = '\0';
09298 if (cmd < 0 || cmd == 't' || cmd == '#')
09299 return cmd;
09300 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09301 if (cmd < 0 || cmd == 't' || cmd == '#')
09302 return cmd;
09303 if (!strcmp(newpassword, newpassword2))
09304 break;
09305 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09306 cmd = ast_play_and_wait(chan, vm_mismatch);
09307 }
09308 if (++tries == 3)
09309 return -1;
09310 if (cmd != 0) {
09311 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09312 }
09313 }
09314 if (pwdchange & PWDCHANGE_INTERNAL)
09315 vm_change_password(vmu, newpassword);
09316 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09317 vm_change_password_shell(vmu, newpassword);
09318
09319 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09320 cmd = ast_play_and_wait(chan, vm_passchanged);
09321
09322 return cmd;
09323 }
09324
09325 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09326 {
09327 int cmd = 0;
09328 int retries = 0;
09329 int duration = 0;
09330 char newpassword[80] = "";
09331 char newpassword2[80] = "";
09332 char prefile[PATH_MAX] = "";
09333 unsigned char buf[256];
09334 int bytes = 0;
09335
09336 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
09337 if (ast_adsi_available(chan)) {
09338 bytes += adsi_logo(buf + bytes);
09339 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09340 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09341 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09342 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09343 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09344 }
09345 while ((cmd >= 0) && (cmd != 't')) {
09346 if (cmd)
09347 retries = 0;
09348 switch (cmd) {
09349 case '1':
09350 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09351 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09352 break;
09353 case '2':
09354 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09355 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09356 break;
09357 case '3':
09358 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09359 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09360 break;
09361 case '4':
09362 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09363 break;
09364 case '5':
09365 if (vmu->password[0] == '-') {
09366 cmd = ast_play_and_wait(chan, "vm-no");
09367 break;
09368 }
09369 newpassword[1] = '\0';
09370 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09371 if (cmd == '#')
09372 newpassword[0] = '\0';
09373 else {
09374 if (cmd < 0)
09375 break;
09376 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09377 break;
09378 }
09379 }
09380 cmd = check_password(vmu, newpassword);
09381 if (cmd != 0) {
09382 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09383 cmd = ast_play_and_wait(chan, vm_invalid_password);
09384 if (!cmd) {
09385 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09386 }
09387 break;
09388 }
09389 newpassword2[1] = '\0';
09390 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09391 if (cmd == '#')
09392 newpassword2[0] = '\0';
09393 else {
09394 if (cmd < 0)
09395 break;
09396
09397 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09398 break;
09399 }
09400 }
09401 if (strcmp(newpassword, newpassword2)) {
09402 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09403 cmd = ast_play_and_wait(chan, vm_mismatch);
09404 if (!cmd) {
09405 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09406 }
09407 break;
09408 }
09409
09410 if (pwdchange & PWDCHANGE_INTERNAL) {
09411 vm_change_password(vmu, newpassword);
09412 }
09413 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
09414 vm_change_password_shell(vmu, newpassword);
09415 }
09416
09417 ast_debug(1, "User %s set password to %s of length %d\n",
09418 vms->username, newpassword, (int) strlen(newpassword));
09419 cmd = ast_play_and_wait(chan, vm_passchanged);
09420 break;
09421 case '*':
09422 cmd = 't';
09423 break;
09424 default:
09425 cmd = 0;
09426 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09427 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09428 if (ast_fileexists(prefile, NULL, NULL)) {
09429 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09430 }
09431 DISPOSE(prefile, -1);
09432 if (!cmd) {
09433 cmd = ast_play_and_wait(chan, "vm-options");
09434 }
09435 if (!cmd) {
09436 cmd = ast_waitfordigit(chan, 6000);
09437 }
09438 if (!cmd) {
09439 retries++;
09440 }
09441 if (retries > 3) {
09442 cmd = 't';
09443 }
09444 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09445 }
09446 }
09447 if (cmd == 't')
09448 cmd = 0;
09449 return cmd;
09450 }
09451
09452
09453
09454
09455
09456
09457
09458
09459
09460
09461
09462
09463
09464
09465
09466
09467
09468 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09469 {
09470 int cmd = 0;
09471 int retries = 0;
09472 int duration = 0;
09473 char prefile[PATH_MAX] = "";
09474 unsigned char buf[256];
09475 int bytes = 0;
09476
09477 if (ast_adsi_available(chan)) {
09478 bytes += adsi_logo(buf + bytes);
09479 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09480 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09481 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09482 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09483 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09484 }
09485
09486 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
09487 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09488 while ((cmd >= 0) && (cmd != 't')) {
09489 if (cmd)
09490 retries = 0;
09491 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09492 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09493 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09494 if (cmd == -1) {
09495 break;
09496 }
09497 cmd = 't';
09498 } else {
09499 switch (cmd) {
09500 case '1':
09501 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09502 break;
09503 case '2':
09504 DELETE(prefile, -1, prefile, vmu);
09505 ast_play_and_wait(chan, "vm-tempremoved");
09506 cmd = 't';
09507 break;
09508 case '*':
09509 cmd = 't';
09510 break;
09511 default:
09512 cmd = ast_play_and_wait(chan,
09513 ast_fileexists(prefile, NULL, NULL) > 0 ?
09514 "vm-tempgreeting2" : "vm-tempgreeting");
09515 if (!cmd) {
09516 cmd = ast_waitfordigit(chan, 6000);
09517 }
09518 if (!cmd) {
09519 retries++;
09520 }
09521 if (retries > 3) {
09522 cmd = 't';
09523 }
09524 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09525 }
09526 }
09527 DISPOSE(prefile, -1);
09528 }
09529 if (cmd == 't')
09530 cmd = 0;
09531 return cmd;
09532 }
09533
09534
09535
09536
09537
09538
09539
09540
09541
09542 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09543 {
09544 int cmd = 0;
09545
09546 if (vms->lastmsg > -1) {
09547 cmd = play_message(chan, vmu, vms);
09548 } else {
09549 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09550 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09551 if (!cmd) {
09552 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09553 cmd = ast_play_and_wait(chan, vms->fn);
09554 }
09555 if (!cmd)
09556 cmd = ast_play_and_wait(chan, "vm-messages");
09557 } else {
09558 if (!cmd)
09559 cmd = ast_play_and_wait(chan, "vm-messages");
09560 if (!cmd) {
09561 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09562 cmd = ast_play_and_wait(chan, vms->fn);
09563 }
09564 }
09565 }
09566 return cmd;
09567 }
09568
09569
09570 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09571 {
09572 int cmd = 0;
09573
09574 if (vms->lastmsg > -1) {
09575 cmd = play_message(chan, vmu, vms);
09576 } else {
09577 if (!strcasecmp(vms->fn, "INBOX")) {
09578 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09579 } else {
09580 cmd = ast_play_and_wait(chan, "vm-nomessages");
09581 }
09582 }
09583 return cmd;
09584 }
09585
09586
09587
09588
09589
09590
09591
09592
09593
09594 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09595 {
09596 int cmd = 0;
09597
09598 if (vms->lastmsg > -1) {
09599 cmd = play_message(chan, vmu, vms);
09600 } else {
09601 cmd = ast_play_and_wait(chan, "vm-youhave");
09602 if (!cmd)
09603 cmd = ast_play_and_wait(chan, "vm-no");
09604 if (!cmd) {
09605 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09606 cmd = ast_play_and_wait(chan, vms->fn);
09607 }
09608 if (!cmd)
09609 cmd = ast_play_and_wait(chan, "vm-messages");
09610 }
09611 return cmd;
09612 }
09613
09614
09615
09616
09617
09618
09619
09620
09621
09622 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09623 {
09624 int cmd;
09625
09626 if (vms->lastmsg > -1) {
09627 cmd = play_message(chan, vmu, vms);
09628 } else {
09629 cmd = ast_play_and_wait(chan, "vm-no");
09630 if (!cmd)
09631 cmd = ast_play_and_wait(chan, "vm-message");
09632 if (!cmd) {
09633 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09634 cmd = ast_play_and_wait(chan, vms->fn);
09635 }
09636 }
09637 return cmd;
09638 }
09639
09640
09641
09642
09643
09644
09645
09646
09647
09648 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09649 {
09650 int cmd;
09651
09652 if (vms->lastmsg > -1) {
09653 cmd = play_message(chan, vmu, vms);
09654 } else {
09655 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09656 if (!cmd)
09657 cmd = ast_play_and_wait(chan, "vm-messages");
09658 if (!cmd) {
09659 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09660 cmd = ast_play_and_wait(chan, vms->fn);
09661 }
09662 }
09663 return cmd;
09664 }
09665
09666
09667
09668
09669
09670
09671
09672
09673
09674 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09675 {
09676 int cmd;
09677
09678 if (vms->lastmsg > -1) {
09679 cmd = play_message(chan, vmu, vms);
09680 } else {
09681 cmd = ast_play_and_wait(chan, "vm-no");
09682 if (!cmd) {
09683 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09684 cmd = ast_play_and_wait(chan, vms->fn);
09685 }
09686 if (!cmd)
09687 cmd = ast_play_and_wait(chan, "vm-messages");
09688 }
09689 return cmd;
09690 }
09691
09692
09693
09694
09695
09696
09697
09698
09699
09700 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09701 {
09702 int cmd;
09703
09704 if (vms->lastmsg > -1) {
09705 cmd = play_message(chan, vmu, vms);
09706 } else {
09707 cmd = ast_play_and_wait(chan, "vm-you");
09708 if (!cmd)
09709 cmd = ast_play_and_wait(chan, "vm-haveno");
09710 if (!cmd)
09711 cmd = ast_play_and_wait(chan, "vm-messages");
09712 if (!cmd) {
09713 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09714 cmd = ast_play_and_wait(chan, vms->fn);
09715 }
09716 }
09717 return cmd;
09718 }
09719
09720
09721
09722
09723
09724
09725
09726
09727
09728 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09729 {
09730 int cmd = 0;
09731
09732 if (vms->lastmsg > -1) {
09733 cmd = play_message(chan, vmu, vms);
09734 } else {
09735 cmd = ast_play_and_wait(chan, "vm-no");
09736 if (!cmd) {
09737 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09738 cmd = ast_play_and_wait(chan, vms->fn);
09739 }
09740 }
09741 return cmd;
09742 }
09743
09744
09745
09746
09747
09748
09749
09750
09751
09752
09753
09754
09755 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09756 {
09757 if (!strncasecmp(chan->language, "es", 2)) {
09758 return vm_browse_messages_es(chan, vms, vmu);
09759 } else if (!strncasecmp(chan->language, "gr", 2)) {
09760 return vm_browse_messages_gr(chan, vms, vmu);
09761 } else if (!strncasecmp(chan->language, "he", 2)) {
09762 return vm_browse_messages_he(chan, vms, vmu);
09763 } else if (!strncasecmp(chan->language, "it", 2)) {
09764 return vm_browse_messages_it(chan, vms, vmu);
09765 } else if (!strncasecmp(chan->language, "pt", 2)) {
09766 return vm_browse_messages_pt(chan, vms, vmu);
09767 } else if (!strncasecmp(chan->language, "vi", 2)) {
09768 return vm_browse_messages_vi(chan, vms, vmu);
09769 } else if (!strncasecmp(chan->language, "zh", 2)) {
09770 return vm_browse_messages_zh(chan, vms, vmu);
09771 } else {
09772 return vm_browse_messages_en(chan, vms, vmu);
09773 }
09774 }
09775
09776 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09777 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09778 int skipuser, int max_logins, int silent)
09779 {
09780 int useadsi = 0, valid = 0, logretries = 0;
09781 char password[AST_MAX_EXTENSION]="", *passptr;
09782 struct ast_vm_user vmus, *vmu = NULL;
09783
09784
09785 adsi_begin(chan, &useadsi);
09786 if (!skipuser && useadsi)
09787 adsi_login(chan);
09788 ast_test_suite_event_notify("PLAYBACK", "Message: vm-login");
09789 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09790 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09791 return -1;
09792 }
09793
09794
09795
09796 while (!valid && (logretries < max_logins)) {
09797
09798 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09799 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09800 return -1;
09801 }
09802 if (ast_strlen_zero(mailbox)) {
09803 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09804 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09805 } else {
09806 ast_verb(3, "Username not entered\n");
09807 return -1;
09808 }
09809 } else if (mailbox[0] == '*') {
09810
09811 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09812 if (ast_exists_extension(chan, chan->context, "a", 1,
09813 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09814 return -1;
09815 }
09816 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09817 mailbox[0] = '\0';
09818 }
09819
09820 if (useadsi)
09821 adsi_password(chan);
09822
09823 if (!ast_strlen_zero(prefix)) {
09824 char fullusername[80] = "";
09825 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09826 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09827 ast_copy_string(mailbox, fullusername, mailbox_size);
09828 }
09829
09830 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09831 vmu = find_user(&vmus, context, mailbox);
09832 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09833
09834 password[0] = '\0';
09835 } else {
09836 ast_test_suite_event_notify("PLAYBACK", "Message: %s", vm_password);
09837 if (ast_streamfile(chan, vm_password, chan->language)) {
09838 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09839 return -1;
09840 }
09841 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09842 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09843 return -1;
09844 } else if (password[0] == '*') {
09845
09846 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
09847 if (ast_exists_extension(chan, chan->context, "a", 1,
09848 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09849 mailbox[0] = '*';
09850 return -1;
09851 }
09852 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09853 mailbox[0] = '\0';
09854
09855 vmu = NULL;
09856 }
09857 }
09858
09859 if (vmu) {
09860 passptr = vmu->password;
09861 if (passptr[0] == '-') passptr++;
09862 }
09863 if (vmu && !strcmp(passptr, password))
09864 valid++;
09865 else {
09866 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09867 if (!ast_strlen_zero(prefix))
09868 mailbox[0] = '\0';
09869 }
09870 logretries++;
09871 if (!valid) {
09872 if (skipuser || logretries >= max_logins) {
09873 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect");
09874 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09875 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09876 return -1;
09877 }
09878 } else {
09879 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect-mailbox");
09880 if (useadsi)
09881 adsi_login(chan);
09882 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09883 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09884 return -1;
09885 }
09886 }
09887 if (ast_waitstream(chan, ""))
09888 return -1;
09889 }
09890 }
09891 if (!valid && (logretries >= max_logins)) {
09892 ast_stopstream(chan);
09893 ast_play_and_wait(chan, "vm-goodbye");
09894 return -1;
09895 }
09896 if (vmu && !skipuser) {
09897 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09898 }
09899 return 0;
09900 }
09901
09902 static int vm_execmain(struct ast_channel *chan, const char *data)
09903 {
09904
09905
09906
09907 int res = -1;
09908 int cmd = 0;
09909 int valid = 0;
09910 char prefixstr[80] ="";
09911 char ext_context[256]="";
09912 int box;
09913 int useadsi = 0;
09914 int skipuser = 0;
09915 struct vm_state vms;
09916 struct ast_vm_user *vmu = NULL, vmus;
09917 char *context = NULL;
09918 int silentexit = 0;
09919 struct ast_flags flags = { 0 };
09920 signed char record_gain = 0;
09921 int play_auto = 0;
09922 int play_folder = 0;
09923 int in_urgent = 0;
09924 #ifdef IMAP_STORAGE
09925 int deleted = 0;
09926 #endif
09927
09928
09929 memset(&vms, 0, sizeof(vms));
09930
09931 vms.lastmsg = -1;
09932
09933 memset(&vmus, 0, sizeof(vmus));
09934
09935 ast_test_suite_event_notify("START", "Message: vm_execmain started");
09936 if (chan->_state != AST_STATE_UP) {
09937 ast_debug(1, "Before ast_answer\n");
09938 ast_answer(chan);
09939 }
09940
09941 if (!ast_strlen_zero(data)) {
09942 char *opts[OPT_ARG_ARRAY_SIZE];
09943 char *parse;
09944 AST_DECLARE_APP_ARGS(args,
09945 AST_APP_ARG(argv0);
09946 AST_APP_ARG(argv1);
09947 );
09948
09949 parse = ast_strdupa(data);
09950
09951 AST_STANDARD_APP_ARGS(args, parse);
09952
09953 if (args.argc == 2) {
09954 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09955 return -1;
09956 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09957 int gain;
09958 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09959 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09960 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09961 return -1;
09962 } else {
09963 record_gain = (signed char) gain;
09964 }
09965 } else {
09966 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09967 }
09968 }
09969 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09970 play_auto = 1;
09971 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
09972
09973 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
09974 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09975 play_folder = -1;
09976 }
09977 } else {
09978 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
09979 }
09980 } else {
09981 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
09982 }
09983 if (play_folder > 9 || play_folder < 0) {
09984 ast_log(AST_LOG_WARNING,
09985 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
09986 opts[OPT_ARG_PLAYFOLDER]);
09987 play_folder = 0;
09988 }
09989 }
09990 } else {
09991
09992 while (*(args.argv0)) {
09993 if (*(args.argv0) == 's')
09994 ast_set_flag(&flags, OPT_SILENT);
09995 else if (*(args.argv0) == 'p')
09996 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
09997 else
09998 break;
09999 (args.argv0)++;
10000 }
10001
10002 }
10003
10004 valid = ast_test_flag(&flags, OPT_SILENT);
10005
10006 if ((context = strchr(args.argv0, '@')))
10007 *context++ = '\0';
10008
10009 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
10010 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
10011 else
10012 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
10013
10014 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
10015 skipuser++;
10016 else
10017 valid = 0;
10018 }
10019
10020 if (!valid)
10021 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
10022
10023 ast_debug(1, "After vm_authenticate\n");
10024
10025 if (vms.username[0] == '*') {
10026 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
10027
10028
10029 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
10030 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
10031 res = 0;
10032 goto out;
10033 }
10034 }
10035
10036 if (!res) {
10037 valid = 1;
10038 if (!skipuser)
10039 vmu = &vmus;
10040 } else {
10041 res = 0;
10042 }
10043
10044
10045 adsi_begin(chan, &useadsi);
10046
10047 ast_test_suite_assert(valid);
10048 if (!valid) {
10049 goto out;
10050 }
10051 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
10052
10053 #ifdef IMAP_STORAGE
10054 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10055 pthread_setspecific(ts_vmstate.key, &vms);
10056
10057 vms.interactive = 1;
10058 vms.updated = 1;
10059 if (vmu)
10060 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10061 vmstate_insert(&vms);
10062 init_vm_state(&vms);
10063 #endif
10064
10065
10066 if (!ast_strlen_zero(vmu->language))
10067 ast_string_field_set(chan, language, vmu->language);
10068
10069
10070 ast_debug(1, "Before open_mailbox\n");
10071 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10072 if (res < 0)
10073 goto out;
10074 vms.oldmessages = vms.lastmsg + 1;
10075 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10076
10077 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10078 if (res < 0)
10079 goto out;
10080 vms.newmessages = vms.lastmsg + 1;
10081 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10082
10083 in_urgent = 1;
10084 res = open_mailbox(&vms, vmu, 11);
10085 if (res < 0)
10086 goto out;
10087 vms.urgentmessages = vms.lastmsg + 1;
10088 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10089
10090
10091 if (play_auto) {
10092 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10093 if (vms.urgentmessages) {
10094 in_urgent = 1;
10095 res = open_mailbox(&vms, vmu, 11);
10096 } else {
10097 in_urgent = 0;
10098 res = open_mailbox(&vms, vmu, play_folder);
10099 }
10100 if (res < 0)
10101 goto out;
10102
10103
10104 if (vms.lastmsg == -1) {
10105 in_urgent = 0;
10106 cmd = vm_browse_messages(chan, &vms, vmu);
10107 res = 0;
10108 goto out;
10109 }
10110 } else {
10111 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10112
10113 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10114 in_urgent = 0;
10115 play_folder = 1;
10116 if (res < 0)
10117 goto out;
10118 } else if (!vms.urgentmessages && vms.newmessages) {
10119
10120 in_urgent = 0;
10121 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10122 if (res < 0)
10123 goto out;
10124 }
10125 }
10126
10127 if (useadsi)
10128 adsi_status(chan, &vms);
10129 res = 0;
10130
10131
10132 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10133 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10134 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10135 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10136 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10137 if ((cmd == 't') || (cmd == '#')) {
10138
10139 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10140 res = 0;
10141 goto out;
10142 } else if (cmd < 0) {
10143
10144 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10145 res = -1;
10146 goto out;
10147 }
10148 }
10149 #ifdef IMAP_STORAGE
10150 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10151 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10152 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10153 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10154 }
10155 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10156 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10157 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10158 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10159 }
10160 #endif
10161
10162 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10163 if (play_auto) {
10164 cmd = '1';
10165 } else {
10166 cmd = vm_intro(chan, vmu, &vms);
10167 }
10168 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10169
10170 vms.repeats = 0;
10171 vms.starting = 1;
10172 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10173
10174 switch (cmd) {
10175 case '1':
10176 vms.curmsg = 0;
10177
10178 case '5':
10179 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10180 cmd = vm_browse_messages(chan, &vms, vmu);
10181 break;
10182 case '2':
10183 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10184 if (useadsi)
10185 adsi_folders(chan, 0, "Change to folder...");
10186
10187 cmd = get_folder2(chan, "vm-changeto", 0);
10188 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10189 if (cmd == '#') {
10190 cmd = 0;
10191 } else if (cmd > 0) {
10192 cmd = cmd - '0';
10193 res = close_mailbox(&vms, vmu);
10194 if (res == ERROR_LOCK_PATH)
10195 goto out;
10196
10197 if (cmd != 11) in_urgent = 0;
10198 res = open_mailbox(&vms, vmu, cmd);
10199 if (res < 0)
10200 goto out;
10201 play_folder = cmd;
10202 cmd = 0;
10203 }
10204 if (useadsi)
10205 adsi_status2(chan, &vms);
10206
10207 if (!cmd) {
10208 cmd = vm_play_folder_name(chan, vms.vmbox);
10209 }
10210
10211 vms.starting = 1;
10212 vms.curmsg = 0;
10213 break;
10214 case '3':
10215 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10216 cmd = 0;
10217 vms.repeats = 0;
10218 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10219 switch (cmd) {
10220 case '1':
10221 if (vms.lastmsg > -1 && !vms.starting) {
10222 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10223 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10224 res = cmd;
10225 goto out;
10226 }
10227 } else {
10228 cmd = ast_play_and_wait(chan, "vm-sorry");
10229 }
10230 cmd = 't';
10231 break;
10232 case '2':
10233 if (!vms.starting)
10234 ast_verb(3, "Callback Requested\n");
10235 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10236 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10237 if (cmd == 9) {
10238 silentexit = 1;
10239 goto out;
10240 } else if (cmd == ERROR_LOCK_PATH) {
10241 res = cmd;
10242 goto out;
10243 }
10244 } else {
10245 cmd = ast_play_and_wait(chan, "vm-sorry");
10246 }
10247 cmd = 't';
10248 break;
10249 case '3':
10250 if (vms.lastmsg > -1 && !vms.starting) {
10251 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10252 if (cmd == ERROR_LOCK_PATH) {
10253 res = cmd;
10254 goto out;
10255 }
10256 } else {
10257 cmd = ast_play_and_wait(chan, "vm-sorry");
10258 }
10259 cmd = 't';
10260 break;
10261 case '4':
10262 if (!ast_strlen_zero(vmu->dialout)) {
10263 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10264 if (cmd == 9) {
10265 silentexit = 1;
10266 goto out;
10267 }
10268 } else {
10269 cmd = ast_play_and_wait(chan, "vm-sorry");
10270 }
10271 cmd = 't';
10272 break;
10273
10274 case '5':
10275 if (ast_test_flag(vmu, VM_SVMAIL)) {
10276 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10277 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10278 res = cmd;
10279 goto out;
10280 }
10281 } else {
10282 cmd = ast_play_and_wait(chan, "vm-sorry");
10283 }
10284 cmd = 't';
10285 break;
10286
10287 case '*':
10288 cmd = 't';
10289 break;
10290
10291 default:
10292 cmd = 0;
10293 if (!vms.starting) {
10294 cmd = ast_play_and_wait(chan, "vm-toreply");
10295 }
10296 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10297 cmd = ast_play_and_wait(chan, "vm-tocallback");
10298 }
10299 if (!cmd && !vms.starting) {
10300 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10301 }
10302 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10303 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10304 }
10305 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10306 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10307 }
10308 if (!cmd) {
10309 cmd = ast_play_and_wait(chan, "vm-starmain");
10310 }
10311 if (!cmd) {
10312 cmd = ast_waitfordigit(chan, 6000);
10313 }
10314 if (!cmd) {
10315 vms.repeats++;
10316 }
10317 if (vms.repeats > 3) {
10318 cmd = 't';
10319 }
10320 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10321 }
10322 }
10323 if (cmd == 't') {
10324 cmd = 0;
10325 vms.repeats = 0;
10326 }
10327 break;
10328 case '4':
10329 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10330 if (vms.curmsg > 0) {
10331 vms.curmsg--;
10332 cmd = play_message(chan, vmu, &vms);
10333 } else {
10334
10335
10336
10337
10338 if (in_urgent == 0 && vms.urgentmessages > 0) {
10339
10340 in_urgent = 1;
10341 res = close_mailbox(&vms, vmu);
10342 if (res == ERROR_LOCK_PATH)
10343 goto out;
10344 res = open_mailbox(&vms, vmu, 11);
10345 if (res < 0)
10346 goto out;
10347 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10348 vms.curmsg = vms.lastmsg;
10349 if (vms.lastmsg < 0) {
10350 cmd = ast_play_and_wait(chan, "vm-nomore");
10351 }
10352 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10353 vms.curmsg = vms.lastmsg;
10354 cmd = play_message(chan, vmu, &vms);
10355 } else {
10356 cmd = ast_play_and_wait(chan, "vm-nomore");
10357 }
10358 }
10359 break;
10360 case '6':
10361 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10362 if (vms.curmsg < vms.lastmsg) {
10363 vms.curmsg++;
10364 cmd = play_message(chan, vmu, &vms);
10365 } else {
10366 if (in_urgent && vms.newmessages > 0) {
10367
10368
10369
10370
10371 in_urgent = 0;
10372 res = close_mailbox(&vms, vmu);
10373 if (res == ERROR_LOCK_PATH)
10374 goto out;
10375 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10376 if (res < 0)
10377 goto out;
10378 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10379 vms.curmsg = -1;
10380 if (vms.lastmsg < 0) {
10381 cmd = ast_play_and_wait(chan, "vm-nomore");
10382 }
10383 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10384 vms.curmsg = 0;
10385 cmd = play_message(chan, vmu, &vms);
10386 } else {
10387 cmd = ast_play_and_wait(chan, "vm-nomore");
10388 }
10389 }
10390 break;
10391 case '7':
10392 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10393 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10394 if (useadsi)
10395 adsi_delete(chan, &vms);
10396 if (vms.deleted[vms.curmsg]) {
10397 if (play_folder == 0) {
10398 if (in_urgent) {
10399 vms.urgentmessages--;
10400 } else {
10401 vms.newmessages--;
10402 }
10403 }
10404 else if (play_folder == 1)
10405 vms.oldmessages--;
10406 cmd = ast_play_and_wait(chan, "vm-deleted");
10407 } else {
10408 if (play_folder == 0) {
10409 if (in_urgent) {
10410 vms.urgentmessages++;
10411 } else {
10412 vms.newmessages++;
10413 }
10414 }
10415 else if (play_folder == 1)
10416 vms.oldmessages++;
10417 cmd = ast_play_and_wait(chan, "vm-undeleted");
10418 }
10419 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10420 if (vms.curmsg < vms.lastmsg) {
10421 vms.curmsg++;
10422 cmd = play_message(chan, vmu, &vms);
10423 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10424 vms.curmsg = 0;
10425 cmd = play_message(chan, vmu, &vms);
10426 } else {
10427
10428
10429
10430
10431 if (in_urgent == 1) {
10432
10433 in_urgent = 0;
10434 res = close_mailbox(&vms, vmu);
10435 if (res == ERROR_LOCK_PATH)
10436 goto out;
10437 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10438 if (res < 0)
10439 goto out;
10440 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10441 vms.curmsg = -1;
10442 if (vms.lastmsg < 0) {
10443 cmd = ast_play_and_wait(chan, "vm-nomore");
10444 }
10445 } else {
10446 cmd = ast_play_and_wait(chan, "vm-nomore");
10447 }
10448 }
10449 }
10450 } else
10451 cmd = 0;
10452 #ifdef IMAP_STORAGE
10453 deleted = 1;
10454 #endif
10455 break;
10456
10457 case '8':
10458 if (vms.lastmsg > -1) {
10459 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10460 if (cmd == ERROR_LOCK_PATH) {
10461 res = cmd;
10462 goto out;
10463 }
10464 } else {
10465
10466
10467
10468
10469 if (in_urgent == 1 && vms.newmessages > 0) {
10470
10471 in_urgent = 0;
10472 res = close_mailbox(&vms, vmu);
10473 if (res == ERROR_LOCK_PATH)
10474 goto out;
10475 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10476 if (res < 0)
10477 goto out;
10478 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10479 vms.curmsg = -1;
10480 if (vms.lastmsg < 0) {
10481 cmd = ast_play_and_wait(chan, "vm-nomore");
10482 }
10483 } else {
10484 cmd = ast_play_and_wait(chan, "vm-nomore");
10485 }
10486 }
10487 break;
10488 case '9':
10489 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10490 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10491
10492 cmd = 0;
10493 break;
10494 }
10495 if (useadsi)
10496 adsi_folders(chan, 1, "Save to folder...");
10497 cmd = get_folder2(chan, "vm-savefolder", 1);
10498 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10499 box = 0;
10500 if (cmd == '#') {
10501 cmd = 0;
10502 break;
10503 } else if (cmd > 0) {
10504 box = cmd = cmd - '0';
10505 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10506 if (cmd == ERROR_LOCK_PATH) {
10507 res = cmd;
10508 goto out;
10509 #ifndef IMAP_STORAGE
10510 } else if (!cmd) {
10511 vms.deleted[vms.curmsg] = 1;
10512 #endif
10513 } else {
10514 vms.deleted[vms.curmsg] = 0;
10515 vms.heard[vms.curmsg] = 0;
10516 }
10517 }
10518 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10519 if (useadsi)
10520 adsi_message(chan, &vms);
10521 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10522 if (!cmd) {
10523 cmd = ast_play_and_wait(chan, "vm-message");
10524 if (!cmd)
10525 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10526 if (!cmd)
10527 cmd = ast_play_and_wait(chan, "vm-savedto");
10528 if (!cmd)
10529 cmd = vm_play_folder_name(chan, vms.fn);
10530 } else {
10531 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10532 }
10533 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10534 if (vms.curmsg < vms.lastmsg) {
10535 vms.curmsg++;
10536 cmd = play_message(chan, vmu, &vms);
10537 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10538 vms.curmsg = 0;
10539 cmd = play_message(chan, vmu, &vms);
10540 } else {
10541
10542
10543
10544
10545 if (in_urgent == 1 && vms.newmessages > 0) {
10546
10547 in_urgent = 0;
10548 res = close_mailbox(&vms, vmu);
10549 if (res == ERROR_LOCK_PATH)
10550 goto out;
10551 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10552 if (res < 0)
10553 goto out;
10554 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10555 vms.curmsg = -1;
10556 if (vms.lastmsg < 0) {
10557 cmd = ast_play_and_wait(chan, "vm-nomore");
10558 }
10559 } else {
10560 cmd = ast_play_and_wait(chan, "vm-nomore");
10561 }
10562 }
10563 }
10564 break;
10565 case '*':
10566 if (!vms.starting) {
10567 cmd = ast_play_and_wait(chan, "vm-onefor");
10568 if (!strncasecmp(chan->language, "he", 2)) {
10569 cmd = ast_play_and_wait(chan, "vm-for");
10570 }
10571 if (!cmd)
10572 cmd = vm_play_folder_name(chan, vms.vmbox);
10573 if (!cmd)
10574 cmd = ast_play_and_wait(chan, "vm-opts");
10575 if (!cmd)
10576 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10577 } else
10578 cmd = 0;
10579 break;
10580 case '0':
10581 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10582 if (useadsi)
10583 adsi_status(chan, &vms);
10584 break;
10585 default:
10586 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10587 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10588 break;
10589 }
10590 }
10591 if ((cmd == 't') || (cmd == '#')) {
10592
10593 res = 0;
10594 } else {
10595
10596 res = -1;
10597 }
10598
10599 out:
10600 if (res > -1) {
10601 ast_stopstream(chan);
10602 adsi_goodbye(chan);
10603 if (valid && res != OPERATOR_EXIT) {
10604 if (silentexit)
10605 res = ast_play_and_wait(chan, "vm-dialout");
10606 else
10607 res = ast_play_and_wait(chan, "vm-goodbye");
10608 }
10609 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10610 res = 0;
10611 }
10612 if (useadsi)
10613 ast_adsi_unload_session(chan);
10614 }
10615 if (vmu)
10616 close_mailbox(&vms, vmu);
10617 if (valid) {
10618 int new = 0, old = 0, urgent = 0;
10619 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10620 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10621
10622 run_externnotify(vmu->context, vmu->mailbox, NULL);
10623 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10624 queue_mwi_event(ext_context, urgent, new, old);
10625 }
10626 #ifdef IMAP_STORAGE
10627
10628 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10629 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10630 ast_mutex_lock(&vms.lock);
10631 #ifdef HAVE_IMAP_TK2006
10632 if (LEVELUIDPLUS (vms.mailstream)) {
10633 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10634 } else
10635 #endif
10636 mail_expunge(vms.mailstream);
10637 ast_mutex_unlock(&vms.lock);
10638 }
10639
10640
10641 if (vmu) {
10642 vmstate_delete(&vms);
10643 }
10644 #endif
10645 if (vmu)
10646 free_user(vmu);
10647
10648 #ifdef IMAP_STORAGE
10649 pthread_setspecific(ts_vmstate.key, NULL);
10650 #endif
10651 return res;
10652 }
10653
10654 static int vm_exec(struct ast_channel *chan, const char *data)
10655 {
10656 int res = 0;
10657 char *tmp;
10658 struct leave_vm_options leave_options;
10659 struct ast_flags flags = { 0 };
10660 char *opts[OPT_ARG_ARRAY_SIZE];
10661 AST_DECLARE_APP_ARGS(args,
10662 AST_APP_ARG(argv0);
10663 AST_APP_ARG(argv1);
10664 );
10665
10666 memset(&leave_options, 0, sizeof(leave_options));
10667
10668 if (chan->_state != AST_STATE_UP)
10669 ast_answer(chan);
10670
10671 if (!ast_strlen_zero(data)) {
10672 tmp = ast_strdupa(data);
10673 AST_STANDARD_APP_ARGS(args, tmp);
10674 if (args.argc == 2) {
10675 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10676 return -1;
10677 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10678 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10679 int gain;
10680
10681 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10682 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10683 return -1;
10684 } else {
10685 leave_options.record_gain = (signed char) gain;
10686 }
10687 }
10688 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10689 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10690 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10691 }
10692 }
10693 } else {
10694 char temp[256];
10695 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10696 if (res < 0)
10697 return res;
10698 if (ast_strlen_zero(temp))
10699 return 0;
10700 args.argv0 = ast_strdupa(temp);
10701 }
10702
10703 res = leave_voicemail(chan, args.argv0, &leave_options);
10704 if (res == 't') {
10705 ast_play_and_wait(chan, "vm-goodbye");
10706 res = 0;
10707 }
10708
10709 if (res == OPERATOR_EXIT) {
10710 res = 0;
10711 }
10712
10713 if (res == ERROR_LOCK_PATH) {
10714 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10715 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10716 res = 0;
10717 }
10718
10719 return res;
10720 }
10721
10722 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10723 {
10724 struct ast_vm_user *vmu;
10725
10726 if (!ast_strlen_zero(box) && box[0] == '*') {
10727 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10728 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10729 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10730 "\n\tand will be ignored.\n", box, context);
10731 return NULL;
10732 }
10733
10734 AST_LIST_TRAVERSE(&users, vmu, list) {
10735 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10736 if (strcasecmp(vmu->context, context)) {
10737 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10738 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10739 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10740 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10741 }
10742 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10743 return NULL;
10744 }
10745 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10746 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10747 return NULL;
10748 }
10749 }
10750
10751 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10752 return NULL;
10753
10754 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10755 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10756
10757 AST_LIST_INSERT_TAIL(&users, vmu, list);
10758
10759 return vmu;
10760 }
10761
10762 static int append_mailbox(const char *context, const char *box, const char *data)
10763 {
10764
10765 char *tmp;
10766 char *stringp;
10767 char *s;
10768 struct ast_vm_user *vmu;
10769 char *mailbox_full;
10770 int new = 0, old = 0, urgent = 0;
10771 char secretfn[PATH_MAX] = "";
10772
10773 tmp = ast_strdupa(data);
10774
10775 if (!(vmu = find_or_create(context, box)))
10776 return -1;
10777
10778 populate_defaults(vmu);
10779
10780 stringp = tmp;
10781 if ((s = strsep(&stringp, ","))) {
10782 if (!ast_strlen_zero(s) && s[0] == '*') {
10783 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10784 "\n\tmust be reset in voicemail.conf.\n", box);
10785 }
10786
10787 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10788 }
10789 if (stringp && (s = strsep(&stringp, ","))) {
10790 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10791 }
10792 if (stringp && (s = strsep(&stringp, ","))) {
10793 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10794 }
10795 if (stringp && (s = strsep(&stringp, ","))) {
10796 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10797 }
10798 if (stringp && (s = strsep(&stringp, ","))) {
10799 apply_options(vmu, s);
10800 }
10801
10802 switch (vmu->passwordlocation) {
10803 case OPT_PWLOC_SPOOLDIR:
10804 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10805 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10806 }
10807
10808 mailbox_full = alloca(strlen(box) + strlen(context) + 1);
10809 strcpy(mailbox_full, box);
10810 strcat(mailbox_full, "@");
10811 strcat(mailbox_full, context);
10812
10813 inboxcount2(mailbox_full, &urgent, &new, &old);
10814 queue_mwi_event(mailbox_full, urgent, new, old);
10815
10816 return 0;
10817 }
10818
10819 AST_TEST_DEFINE(test_voicemail_vmuser)
10820 {
10821 int res = 0;
10822 struct ast_vm_user *vmu;
10823
10824 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10825 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10826 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10827 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10828 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10829 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10830 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10831 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10832 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10833 #ifdef IMAP_STORAGE
10834 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10835 "imapfolder=INBOX|imapvmshareid=6000";
10836 #endif
10837
10838 switch (cmd) {
10839 case TEST_INIT:
10840 info->name = "vmuser";
10841 info->category = "/apps/app_voicemail/";
10842 info->summary = "Vmuser unit test";
10843 info->description =
10844 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10845 return AST_TEST_NOT_RUN;
10846 case TEST_EXECUTE:
10847 break;
10848 }
10849
10850 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10851 return AST_TEST_NOT_RUN;
10852 }
10853 ast_set_flag(vmu, VM_ALLOCED);
10854 populate_defaults(vmu);
10855
10856 apply_options(vmu, options_string);
10857
10858 if (!ast_test_flag(vmu, VM_ATTACH)) {
10859 ast_test_status_update(test, "Parse failure for attach option\n");
10860 res = 1;
10861 }
10862 if (strcasecmp(vmu->attachfmt, "wav49")) {
10863 ast_test_status_update(test, "Parse failure for attachftm option\n");
10864 res = 1;
10865 }
10866 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10867 ast_test_status_update(test, "Parse failure for serveremail option\n");
10868 res = 1;
10869 }
10870 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10871 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10872 res = 1;
10873 }
10874 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10875 ast_test_status_update(test, "Parse failure for emailbody option\n");
10876 res = 1;
10877 }
10878 if (strcasecmp(vmu->zonetag, "central")) {
10879 ast_test_status_update(test, "Parse failure for tz option\n");
10880 res = 1;
10881 }
10882 if (!ast_test_flag(vmu, VM_DELETE)) {
10883 ast_test_status_update(test, "Parse failure for delete option\n");
10884 res = 1;
10885 }
10886 if (!ast_test_flag(vmu, VM_SAYCID)) {
10887 ast_test_status_update(test, "Parse failure for saycid option\n");
10888 res = 1;
10889 }
10890 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10891 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10892 res = 1;
10893 }
10894 if (!ast_test_flag(vmu, VM_REVIEW)) {
10895 ast_test_status_update(test, "Parse failure for review option\n");
10896 res = 1;
10897 }
10898 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10899 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10900 res = 1;
10901 }
10902 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10903 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10904 res = 1;
10905 }
10906 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10907 ast_test_status_update(test, "Parse failure for operator option\n");
10908 res = 1;
10909 }
10910 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10911 ast_test_status_update(test, "Parse failure for envelope option\n");
10912 res = 1;
10913 }
10914 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10915 ast_test_status_update(test, "Parse failure for moveheard option\n");
10916 res = 1;
10917 }
10918 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10919 ast_test_status_update(test, "Parse failure for sayduration option\n");
10920 res = 1;
10921 }
10922 if (vmu->saydurationm != 5) {
10923 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10924 res = 1;
10925 }
10926 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10927 ast_test_status_update(test, "Parse failure for forcename option\n");
10928 res = 1;
10929 }
10930 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10931 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10932 res = 1;
10933 }
10934 if (strcasecmp(vmu->callback, "somecontext")) {
10935 ast_test_status_update(test, "Parse failure for callbacks option\n");
10936 res = 1;
10937 }
10938 if (strcasecmp(vmu->dialout, "somecontext2")) {
10939 ast_test_status_update(test, "Parse failure for dialout option\n");
10940 res = 1;
10941 }
10942 if (strcasecmp(vmu->exit, "somecontext3")) {
10943 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10944 res = 1;
10945 }
10946 if (vmu->minsecs != 10) {
10947 ast_test_status_update(test, "Parse failure for minsecs option\n");
10948 res = 1;
10949 }
10950 if (vmu->maxsecs != 100) {
10951 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10952 res = 1;
10953 }
10954 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10955 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10956 res = 1;
10957 }
10958 if (vmu->maxdeletedmsg != 50) {
10959 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10960 res = 1;
10961 }
10962 if (vmu->volgain != 1.3) {
10963 ast_test_status_update(test, "Parse failure for volgain option\n");
10964 res = 1;
10965 }
10966 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10967 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10968 res = 1;
10969 }
10970 #ifdef IMAP_STORAGE
10971 apply_options(vmu, option_string2);
10972
10973 if (strcasecmp(vmu->imapuser, "imapuser")) {
10974 ast_test_status_update(test, "Parse failure for imapuser option\n");
10975 res = 1;
10976 }
10977 if (strcasecmp(vmu->imappassword, "imappasswd")) {
10978 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10979 res = 1;
10980 }
10981 if (strcasecmp(vmu->imapfolder, "INBOX")) {
10982 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10983 res = 1;
10984 }
10985 if (strcasecmp(vmu->imapvmshareid, "6000")) {
10986 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
10987 res = 1;
10988 }
10989 #endif
10990
10991 free_user(vmu);
10992 return res ? AST_TEST_FAIL : AST_TEST_PASS;
10993 }
10994
10995 static int vm_box_exists(struct ast_channel *chan, const char *data)
10996 {
10997 struct ast_vm_user svm;
10998 char *context, *box;
10999 AST_DECLARE_APP_ARGS(args,
11000 AST_APP_ARG(mbox);
11001 AST_APP_ARG(options);
11002 );
11003 static int dep_warning = 0;
11004
11005 if (ast_strlen_zero(data)) {
11006 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
11007 return -1;
11008 }
11009
11010 if (!dep_warning) {
11011 dep_warning = 1;
11012 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
11013 }
11014
11015 box = ast_strdupa(data);
11016
11017 AST_STANDARD_APP_ARGS(args, box);
11018
11019 if (args.options) {
11020 }
11021
11022 if ((context = strchr(args.mbox, '@'))) {
11023 *context = '\0';
11024 context++;
11025 }
11026
11027 if (find_user(&svm, context, args.mbox)) {
11028 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
11029 } else
11030 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
11031
11032 return 0;
11033 }
11034
11035 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
11036 {
11037 struct ast_vm_user svm;
11038 AST_DECLARE_APP_ARGS(arg,
11039 AST_APP_ARG(mbox);
11040 AST_APP_ARG(context);
11041 );
11042
11043 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
11044
11045 if (ast_strlen_zero(arg.mbox)) {
11046 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11047 return -1;
11048 }
11049
11050 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
11051 return 0;
11052 }
11053
11054 static struct ast_custom_function mailbox_exists_acf = {
11055 .name = "MAILBOX_EXISTS",
11056 .read = acf_mailbox_exists,
11057 };
11058
11059 static int vmauthenticate(struct ast_channel *chan, const char *data)
11060 {
11061 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11062 struct ast_vm_user vmus;
11063 char *options = NULL;
11064 int silent = 0, skipuser = 0;
11065 int res = -1;
11066
11067 if (data) {
11068 s = ast_strdupa(data);
11069 user = strsep(&s, ",");
11070 options = strsep(&s, ",");
11071 if (user) {
11072 s = user;
11073 user = strsep(&s, "@");
11074 context = strsep(&s, "");
11075 if (!ast_strlen_zero(user))
11076 skipuser++;
11077 ast_copy_string(mailbox, user, sizeof(mailbox));
11078 }
11079 }
11080
11081 if (options) {
11082 silent = (strchr(options, 's')) != NULL;
11083 }
11084
11085 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11086 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11087 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11088 ast_play_and_wait(chan, "auth-thankyou");
11089 res = 0;
11090 } else if (mailbox[0] == '*') {
11091
11092 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11093 res = 0;
11094 }
11095 }
11096
11097 return res;
11098 }
11099
11100 static char *show_users_realtime(int fd, const char *context)
11101 {
11102 struct ast_config *cfg;
11103 const char *cat = NULL;
11104
11105 if (!(cfg = ast_load_realtime_multientry("voicemail",
11106 "context", context, SENTINEL))) {
11107 return CLI_FAILURE;
11108 }
11109
11110 ast_cli(fd,
11111 "\n"
11112 "=============================================================\n"
11113 "=== Configured Voicemail Users ==============================\n"
11114 "=============================================================\n"
11115 "===\n");
11116
11117 while ((cat = ast_category_browse(cfg, cat))) {
11118 struct ast_variable *var = NULL;
11119 ast_cli(fd,
11120 "=== Mailbox ...\n"
11121 "===\n");
11122 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11123 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11124 ast_cli(fd,
11125 "===\n"
11126 "=== ---------------------------------------------------------\n"
11127 "===\n");
11128 }
11129
11130 ast_cli(fd,
11131 "=============================================================\n"
11132 "\n");
11133
11134 ast_config_destroy(cfg);
11135
11136 return CLI_SUCCESS;
11137 }
11138
11139 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11140 {
11141 int which = 0;
11142 int wordlen;
11143 struct ast_vm_user *vmu;
11144 const char *context = "";
11145
11146
11147 if (pos > 4)
11148 return NULL;
11149 if (pos == 3)
11150 return (state == 0) ? ast_strdup("for") : NULL;
11151 wordlen = strlen(word);
11152 AST_LIST_TRAVERSE(&users, vmu, list) {
11153 if (!strncasecmp(word, vmu->context, wordlen)) {
11154 if (context && strcmp(context, vmu->context) && ++which > state)
11155 return ast_strdup(vmu->context);
11156
11157 context = vmu->context;
11158 }
11159 }
11160 return NULL;
11161 }
11162
11163
11164 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11165 {
11166 struct ast_vm_user *vmu;
11167 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11168 const char *context = NULL;
11169 int users_counter = 0;
11170
11171 switch (cmd) {
11172 case CLI_INIT:
11173 e->command = "voicemail show users";
11174 e->usage =
11175 "Usage: voicemail show users [for <context>]\n"
11176 " Lists all mailboxes currently set up\n";
11177 return NULL;
11178 case CLI_GENERATE:
11179 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11180 }
11181
11182 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11183 return CLI_SHOWUSAGE;
11184 if (a->argc == 5) {
11185 if (strcmp(a->argv[3],"for"))
11186 return CLI_SHOWUSAGE;
11187 context = a->argv[4];
11188 }
11189
11190 if (ast_check_realtime("voicemail")) {
11191 if (!context) {
11192 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11193 return CLI_SHOWUSAGE;
11194 }
11195 return show_users_realtime(a->fd, context);
11196 }
11197
11198 AST_LIST_LOCK(&users);
11199 if (AST_LIST_EMPTY(&users)) {
11200 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11201 AST_LIST_UNLOCK(&users);
11202 return CLI_FAILURE;
11203 }
11204 if (!context) {
11205 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11206 } else {
11207 int count = 0;
11208 AST_LIST_TRAVERSE(&users, vmu, list) {
11209 if (!strcmp(context, vmu->context)) {
11210 count++;
11211 break;
11212 }
11213 }
11214 if (count) {
11215 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11216 } else {
11217 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11218 AST_LIST_UNLOCK(&users);
11219 return CLI_FAILURE;
11220 }
11221 }
11222 AST_LIST_TRAVERSE(&users, vmu, list) {
11223 int newmsgs = 0, oldmsgs = 0;
11224 char count[12], tmp[256] = "";
11225
11226 if (!context || !strcmp(context, vmu->context)) {
11227 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11228 inboxcount(tmp, &newmsgs, &oldmsgs);
11229 snprintf(count, sizeof(count), "%d", newmsgs);
11230 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11231 users_counter++;
11232 }
11233 }
11234 AST_LIST_UNLOCK(&users);
11235 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11236 return CLI_SUCCESS;
11237 }
11238
11239
11240 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11241 {
11242 struct vm_zone *zone;
11243 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11244 char *res = CLI_SUCCESS;
11245
11246 switch (cmd) {
11247 case CLI_INIT:
11248 e->command = "voicemail show zones";
11249 e->usage =
11250 "Usage: voicemail show zones\n"
11251 " Lists zone message formats\n";
11252 return NULL;
11253 case CLI_GENERATE:
11254 return NULL;
11255 }
11256
11257 if (a->argc != 3)
11258 return CLI_SHOWUSAGE;
11259
11260 AST_LIST_LOCK(&zones);
11261 if (!AST_LIST_EMPTY(&zones)) {
11262 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11263 AST_LIST_TRAVERSE(&zones, zone, list) {
11264 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11265 }
11266 } else {
11267 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11268 res = CLI_FAILURE;
11269 }
11270 AST_LIST_UNLOCK(&zones);
11271
11272 return res;
11273 }
11274
11275
11276 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11277 {
11278 switch (cmd) {
11279 case CLI_INIT:
11280 e->command = "voicemail reload";
11281 e->usage =
11282 "Usage: voicemail reload\n"
11283 " Reload voicemail configuration\n";
11284 return NULL;
11285 case CLI_GENERATE:
11286 return NULL;
11287 }
11288
11289 if (a->argc != 2)
11290 return CLI_SHOWUSAGE;
11291
11292 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11293 load_config(1);
11294
11295 return CLI_SUCCESS;
11296 }
11297
11298 static struct ast_cli_entry cli_voicemail[] = {
11299 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11300 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11301 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11302 };
11303
11304 #ifdef IMAP_STORAGE
11305 #define DATA_EXPORT_VM_USERS(USER) \
11306 USER(ast_vm_user, context, AST_DATA_STRING) \
11307 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11308 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11309 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11310 USER(ast_vm_user, email, AST_DATA_STRING) \
11311 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11312 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11313 USER(ast_vm_user, pager, AST_DATA_STRING) \
11314 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11315 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11316 USER(ast_vm_user, language, AST_DATA_STRING) \
11317 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11318 USER(ast_vm_user, callback, AST_DATA_STRING) \
11319 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11320 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11321 USER(ast_vm_user, exit, AST_DATA_STRING) \
11322 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11323 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11324 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11325 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11326 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11327 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11328 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11329 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11330 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11331 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11332 #else
11333 #define DATA_EXPORT_VM_USERS(USER) \
11334 USER(ast_vm_user, context, AST_DATA_STRING) \
11335 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11336 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11337 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11338 USER(ast_vm_user, email, AST_DATA_STRING) \
11339 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11340 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11341 USER(ast_vm_user, pager, AST_DATA_STRING) \
11342 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11343 USER(ast_vm_user, mailcmd, AST_DATA_STRING) \
11344 USER(ast_vm_user, language, AST_DATA_STRING) \
11345 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11346 USER(ast_vm_user, callback, AST_DATA_STRING) \
11347 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11348 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11349 USER(ast_vm_user, exit, AST_DATA_STRING) \
11350 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11351 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11352 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11353 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11354 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11355 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11356 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11357 #endif
11358
11359 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11360
11361 #define DATA_EXPORT_VM_ZONES(ZONE) \
11362 ZONE(vm_zone, name, AST_DATA_STRING) \
11363 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11364 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11365
11366 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11367
11368
11369
11370
11371
11372
11373
11374
11375 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11376 struct ast_data *data_root, struct ast_vm_user *user)
11377 {
11378 struct ast_data *data_user, *data_zone;
11379 struct ast_data *data_state;
11380 struct vm_zone *zone = NULL;
11381 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11382 char ext_context[256] = "";
11383
11384 data_user = ast_data_add_node(data_root, "user");
11385 if (!data_user) {
11386 return -1;
11387 }
11388
11389 ast_data_add_structure(ast_vm_user, data_user, user);
11390
11391 AST_LIST_LOCK(&zones);
11392 AST_LIST_TRAVERSE(&zones, zone, list) {
11393 if (!strcmp(zone->name, user->zonetag)) {
11394 break;
11395 }
11396 }
11397 AST_LIST_UNLOCK(&zones);
11398
11399
11400 data_state = ast_data_add_node(data_user, "state");
11401 if (!data_state) {
11402 return -1;
11403 }
11404 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11405 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11406 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11407 ast_data_add_int(data_state, "newmsg", newmsg);
11408 ast_data_add_int(data_state, "oldmsg", oldmsg);
11409
11410 if (zone) {
11411 data_zone = ast_data_add_node(data_user, "zone");
11412 ast_data_add_structure(vm_zone, data_zone, zone);
11413 }
11414
11415 if (!ast_data_search_match(search, data_user)) {
11416 ast_data_remove_node(data_root, data_user);
11417 }
11418
11419 return 0;
11420 }
11421
11422 static int vm_users_data_provider_get(const struct ast_data_search *search,
11423 struct ast_data *data_root)
11424 {
11425 struct ast_vm_user *user;
11426
11427 AST_LIST_LOCK(&users);
11428 AST_LIST_TRAVERSE(&users, user, list) {
11429 vm_users_data_provider_get_helper(search, data_root, user);
11430 }
11431 AST_LIST_UNLOCK(&users);
11432
11433 return 0;
11434 }
11435
11436 static const struct ast_data_handler vm_users_data_provider = {
11437 .version = AST_DATA_HANDLER_VERSION,
11438 .get = vm_users_data_provider_get
11439 };
11440
11441 static const struct ast_data_entry vm_data_providers[] = {
11442 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11443 };
11444
11445 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11446 {
11447 int new = 0, old = 0, urgent = 0;
11448
11449 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11450
11451 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11452 mwi_sub->old_urgent = urgent;
11453 mwi_sub->old_new = new;
11454 mwi_sub->old_old = old;
11455 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11456 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11457 }
11458 }
11459
11460 static void poll_subscribed_mailboxes(void)
11461 {
11462 struct mwi_sub *mwi_sub;
11463
11464 AST_RWLIST_RDLOCK(&mwi_subs);
11465 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11466 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11467 poll_subscribed_mailbox(mwi_sub);
11468 }
11469 }
11470 AST_RWLIST_UNLOCK(&mwi_subs);
11471 }
11472
11473 static void *mb_poll_thread(void *data)
11474 {
11475 while (poll_thread_run) {
11476 struct timespec ts = { 0, };
11477 struct timeval wait;
11478
11479 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11480 ts.tv_sec = wait.tv_sec;
11481 ts.tv_nsec = wait.tv_usec * 1000;
11482
11483 ast_mutex_lock(&poll_lock);
11484 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11485 ast_mutex_unlock(&poll_lock);
11486
11487 if (!poll_thread_run)
11488 break;
11489
11490 poll_subscribed_mailboxes();
11491 }
11492
11493 return NULL;
11494 }
11495
11496 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11497 {
11498 ast_free(mwi_sub);
11499 }
11500
11501 static int handle_unsubscribe(void *datap)
11502 {
11503 struct mwi_sub *mwi_sub;
11504 uint32_t *uniqueid = datap;
11505
11506 AST_RWLIST_WRLOCK(&mwi_subs);
11507 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11508 if (mwi_sub->uniqueid == *uniqueid) {
11509 AST_LIST_REMOVE_CURRENT(entry);
11510 break;
11511 }
11512 }
11513 AST_RWLIST_TRAVERSE_SAFE_END
11514 AST_RWLIST_UNLOCK(&mwi_subs);
11515
11516 if (mwi_sub)
11517 mwi_sub_destroy(mwi_sub);
11518
11519 ast_free(uniqueid);
11520 return 0;
11521 }
11522
11523 static int handle_subscribe(void *datap)
11524 {
11525 unsigned int len;
11526 struct mwi_sub *mwi_sub;
11527 struct mwi_sub_task *p = datap;
11528
11529 len = sizeof(*mwi_sub);
11530 if (!ast_strlen_zero(p->mailbox))
11531 len += strlen(p->mailbox);
11532
11533 if (!ast_strlen_zero(p->context))
11534 len += strlen(p->context) + 1;
11535
11536 if (!(mwi_sub = ast_calloc(1, len)))
11537 return -1;
11538
11539 mwi_sub->uniqueid = p->uniqueid;
11540 if (!ast_strlen_zero(p->mailbox))
11541 strcpy(mwi_sub->mailbox, p->mailbox);
11542
11543 if (!ast_strlen_zero(p->context)) {
11544 strcat(mwi_sub->mailbox, "@");
11545 strcat(mwi_sub->mailbox, p->context);
11546 }
11547
11548 AST_RWLIST_WRLOCK(&mwi_subs);
11549 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11550 AST_RWLIST_UNLOCK(&mwi_subs);
11551 ast_free((void *) p->mailbox);
11552 ast_free((void *) p->context);
11553 ast_free(p);
11554 poll_subscribed_mailbox(mwi_sub);
11555 return 0;
11556 }
11557
11558 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11559 {
11560 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11561
11562 if (!uniqueid) {
11563 ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n");
11564 return;
11565 }
11566
11567 if (ast_event_get_type(event) != AST_EVENT_UNSUB) {
11568 ast_free(uniqueid);
11569 return;
11570 }
11571
11572 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI) {
11573 ast_free(uniqueid);
11574 return;
11575 }
11576
11577 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11578 *uniqueid = u;
11579 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11580 ast_free(uniqueid);
11581 }
11582 }
11583
11584 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11585 {
11586 struct mwi_sub_task *mwist;
11587
11588 if (ast_event_get_type(event) != AST_EVENT_SUB)
11589 return;
11590
11591 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11592 return;
11593
11594 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11595 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11596 return;
11597 }
11598 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11599 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11600 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11601
11602 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11603 ast_free(mwist);
11604 }
11605 }
11606
11607 static void start_poll_thread(void)
11608 {
11609 int errcode;
11610 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11611 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11612 AST_EVENT_IE_END);
11613
11614 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11615 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11616 AST_EVENT_IE_END);
11617
11618 if (mwi_sub_sub)
11619 ast_event_report_subs(mwi_sub_sub);
11620
11621 poll_thread_run = 1;
11622
11623 if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL))) {
11624 ast_log(LOG_ERROR, "Could not create thread: %s\n", strerror(errcode));
11625 }
11626 }
11627
11628 static void stop_poll_thread(void)
11629 {
11630 poll_thread_run = 0;
11631
11632 if (mwi_sub_sub) {
11633 ast_event_unsubscribe(mwi_sub_sub);
11634 mwi_sub_sub = NULL;
11635 }
11636
11637 if (mwi_unsub_sub) {
11638 ast_event_unsubscribe(mwi_unsub_sub);
11639 mwi_unsub_sub = NULL;
11640 }
11641
11642 ast_mutex_lock(&poll_lock);
11643 ast_cond_signal(&poll_cond);
11644 ast_mutex_unlock(&poll_lock);
11645
11646 pthread_join(poll_thread, NULL);
11647
11648 poll_thread = AST_PTHREADT_NULL;
11649 }
11650
11651
11652 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11653 {
11654 struct ast_vm_user *vmu = NULL;
11655 const char *id = astman_get_header(m, "ActionID");
11656 char actionid[128] = "";
11657
11658 if (!ast_strlen_zero(id))
11659 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11660
11661 AST_LIST_LOCK(&users);
11662
11663 if (AST_LIST_EMPTY(&users)) {
11664 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11665 AST_LIST_UNLOCK(&users);
11666 return RESULT_SUCCESS;
11667 }
11668
11669 astman_send_ack(s, m, "Voicemail user list will follow");
11670
11671 AST_LIST_TRAVERSE(&users, vmu, list) {
11672 char dirname[256];
11673
11674 #ifdef IMAP_STORAGE
11675 int new, old;
11676 inboxcount(vmu->mailbox, &new, &old);
11677 #endif
11678
11679 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11680 astman_append(s,
11681 "%s"
11682 "Event: VoicemailUserEntry\r\n"
11683 "VMContext: %s\r\n"
11684 "VoiceMailbox: %s\r\n"
11685 "Fullname: %s\r\n"
11686 "Email: %s\r\n"
11687 "Pager: %s\r\n"
11688 "ServerEmail: %s\r\n"
11689 "MailCommand: %s\r\n"
11690 "Language: %s\r\n"
11691 "TimeZone: %s\r\n"
11692 "Callback: %s\r\n"
11693 "Dialout: %s\r\n"
11694 "UniqueID: %s\r\n"
11695 "ExitContext: %s\r\n"
11696 "SayDurationMinimum: %d\r\n"
11697 "SayEnvelope: %s\r\n"
11698 "SayCID: %s\r\n"
11699 "AttachMessage: %s\r\n"
11700 "AttachmentFormat: %s\r\n"
11701 "DeleteMessage: %s\r\n"
11702 "VolumeGain: %.2f\r\n"
11703 "CanReview: %s\r\n"
11704 "CallOperator: %s\r\n"
11705 "MaxMessageCount: %d\r\n"
11706 "MaxMessageLength: %d\r\n"
11707 "NewMessageCount: %d\r\n"
11708 #ifdef IMAP_STORAGE
11709 "OldMessageCount: %d\r\n"
11710 "IMAPUser: %s\r\n"
11711 #endif
11712 "\r\n",
11713 actionid,
11714 vmu->context,
11715 vmu->mailbox,
11716 vmu->fullname,
11717 vmu->email,
11718 vmu->pager,
11719 vmu->serveremail,
11720 vmu->mailcmd,
11721 vmu->language,
11722 vmu->zonetag,
11723 vmu->callback,
11724 vmu->dialout,
11725 vmu->uniqueid,
11726 vmu->exit,
11727 vmu->saydurationm,
11728 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11729 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11730 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11731 vmu->attachfmt,
11732 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11733 vmu->volgain,
11734 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11735 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11736 vmu->maxmsg,
11737 vmu->maxsecs,
11738 #ifdef IMAP_STORAGE
11739 new, old, vmu->imapuser
11740 #else
11741 count_messages(vmu, dirname)
11742 #endif
11743 );
11744 }
11745 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11746
11747 AST_LIST_UNLOCK(&users);
11748
11749 return RESULT_SUCCESS;
11750 }
11751
11752
11753 static void free_vm_users(void)
11754 {
11755 struct ast_vm_user *current;
11756 AST_LIST_LOCK(&users);
11757 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11758 ast_set_flag(current, VM_ALLOCED);
11759 free_user(current);
11760 }
11761 AST_LIST_UNLOCK(&users);
11762 }
11763
11764
11765 static void free_vm_zones(void)
11766 {
11767 struct vm_zone *zcur;
11768 AST_LIST_LOCK(&zones);
11769 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11770 free_zone(zcur);
11771 AST_LIST_UNLOCK(&zones);
11772 }
11773
11774 static const char *substitute_escapes(const char *value)
11775 {
11776 char *current;
11777
11778
11779 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11780
11781 ast_str_reset(str);
11782
11783
11784 for (current = (char *) value; *current; current++) {
11785 if (*current == '\\') {
11786 current++;
11787 if (!*current) {
11788 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11789 break;
11790 }
11791 switch (*current) {
11792 case '\\':
11793 ast_str_append(&str, 0, "\\");
11794 break;
11795 case 'r':
11796 ast_str_append(&str, 0, "\r");
11797 break;
11798 case 'n':
11799 #ifdef IMAP_STORAGE
11800 if (!str->used || str->str[str->used - 1] != '\r') {
11801 ast_str_append(&str, 0, "\r");
11802 }
11803 #endif
11804 ast_str_append(&str, 0, "\n");
11805 break;
11806 case 't':
11807 ast_str_append(&str, 0, "\t");
11808 break;
11809 default:
11810 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11811 break;
11812 }
11813 } else {
11814 ast_str_append(&str, 0, "%c", *current);
11815 }
11816 }
11817
11818 return ast_str_buffer(str);
11819 }
11820
11821 static int load_config(int reload)
11822 {
11823 struct ast_config *cfg, *ucfg;
11824 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11825 int res;
11826
11827 ast_unload_realtime("voicemail");
11828 ast_unload_realtime("voicemail_data");
11829
11830 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11831 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11832 return 0;
11833 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11834 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11835 ucfg = NULL;
11836 }
11837 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11838 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11839 ast_config_destroy(ucfg);
11840 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11841 return 0;
11842 }
11843 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11844 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11845 return 0;
11846 } else {
11847 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11848 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11849 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11850 ucfg = NULL;
11851 }
11852 }
11853
11854 res = actual_load_config(reload, cfg, ucfg);
11855
11856 ast_config_destroy(cfg);
11857 ast_config_destroy(ucfg);
11858
11859 return res;
11860 }
11861
11862 #ifdef TEST_FRAMEWORK
11863 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11864 {
11865 ast_unload_realtime("voicemail");
11866 ast_unload_realtime("voicemail_data");
11867 return actual_load_config(reload, cfg, ucfg);
11868 }
11869 #endif
11870
11871 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11872 {
11873 struct ast_vm_user *current;
11874 char *cat;
11875 struct ast_variable *var;
11876 const char *val;
11877 char *q, *stringp, *tmp;
11878 int x;
11879 int tmpadsi[4];
11880 char secretfn[PATH_MAX] = "";
11881
11882 #ifdef IMAP_STORAGE
11883 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11884 #endif
11885
11886 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11887 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11888 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11889 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11890 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11891
11892
11893 free_vm_users();
11894
11895
11896 free_vm_zones();
11897
11898 AST_LIST_LOCK(&users);
11899
11900 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11901 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11902
11903 if (cfg) {
11904
11905
11906 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11907 val = "default";
11908 ast_copy_string(userscontext, val, sizeof(userscontext));
11909
11910 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11911 val = "yes";
11912 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11913
11914 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11915 val = "no";
11916 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11917
11918 volgain = 0.0;
11919 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11920 sscanf(val, "%30lf", &volgain);
11921
11922 #ifdef ODBC_STORAGE
11923 strcpy(odbc_database, "asterisk");
11924 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11925 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11926 }
11927 strcpy(odbc_table, "voicemessages");
11928 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11929 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11930 }
11931 #endif
11932
11933 strcpy(mailcmd, SENDMAIL);
11934 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11935 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11936
11937 maxsilence = 0;
11938 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11939 maxsilence = atoi(val);
11940 if (maxsilence > 0)
11941 maxsilence *= 1000;
11942 }
11943
11944 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11945 maxmsg = MAXMSG;
11946 } else {
11947 maxmsg = atoi(val);
11948 if (maxmsg < 0) {
11949 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11950 maxmsg = MAXMSG;
11951 } else if (maxmsg > MAXMSGLIMIT) {
11952 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11953 maxmsg = MAXMSGLIMIT;
11954 }
11955 }
11956
11957 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11958 maxdeletedmsg = 0;
11959 } else {
11960 if (sscanf(val, "%30d", &x) == 1)
11961 maxdeletedmsg = x;
11962 else if (ast_true(val))
11963 maxdeletedmsg = MAXMSG;
11964 else
11965 maxdeletedmsg = 0;
11966
11967 if (maxdeletedmsg < 0) {
11968 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11969 maxdeletedmsg = MAXMSG;
11970 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11971 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11972 maxdeletedmsg = MAXMSGLIMIT;
11973 }
11974 }
11975
11976
11977 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
11978 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
11979 }
11980
11981
11982 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
11983 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
11984 }
11985
11986
11987 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
11988 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11989 pwdchange = PWDCHANGE_EXTERNAL;
11990 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
11991 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
11992 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
11993 }
11994
11995
11996 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
11997 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
11998 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
11999 }
12000
12001 #ifdef IMAP_STORAGE
12002
12003 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
12004 ast_copy_string(imapserver, val, sizeof(imapserver));
12005 } else {
12006 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
12007 }
12008
12009 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
12010 ast_copy_string(imapport, val, sizeof(imapport));
12011 } else {
12012 ast_copy_string(imapport, "143", sizeof(imapport));
12013 }
12014
12015 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
12016 ast_copy_string(imapflags, val, sizeof(imapflags));
12017 }
12018
12019 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
12020 ast_copy_string(authuser, val, sizeof(authuser));
12021 }
12022
12023 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
12024 ast_copy_string(authpassword, val, sizeof(authpassword));
12025 }
12026
12027 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
12028 if (ast_false(val))
12029 expungeonhangup = 0;
12030 else
12031 expungeonhangup = 1;
12032 } else {
12033 expungeonhangup = 1;
12034 }
12035
12036 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
12037 ast_copy_string(imapfolder, val, sizeof(imapfolder));
12038 } else {
12039 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
12040 }
12041 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
12042 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
12043 }
12044 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
12045 imapgreetings = ast_true(val);
12046 } else {
12047 imapgreetings = 0;
12048 }
12049 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
12050 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12051 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
12052
12053 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12054 } else {
12055 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
12056 }
12057
12058
12059
12060
12061
12062 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
12063 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
12064 } else {
12065 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
12066 }
12067
12068 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
12069 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
12070 } else {
12071 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
12072 }
12073
12074 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12075 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12076 } else {
12077 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12078 }
12079
12080 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12081 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12082 } else {
12083 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12084 }
12085
12086
12087 imapversion++;
12088 #endif
12089
12090 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12091 ast_copy_string(externnotify, val, sizeof(externnotify));
12092 ast_debug(1, "found externnotify: %s\n", externnotify);
12093 } else {
12094 externnotify[0] = '\0';
12095 }
12096
12097
12098 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12099 ast_debug(1, "Enabled SMDI voicemail notification\n");
12100 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12101 smdi_iface = ast_smdi_interface_find(val);
12102 } else {
12103 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12104 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12105 }
12106 if (!smdi_iface) {
12107 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12108 }
12109 }
12110
12111
12112 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12113 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12114 silencethreshold = atoi(val);
12115
12116 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12117 val = ASTERISK_USERNAME;
12118 ast_copy_string(serveremail, val, sizeof(serveremail));
12119
12120 vmmaxsecs = 0;
12121 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
12122 if (sscanf(val, "%30d", &x) == 1) {
12123 vmmaxsecs = x;
12124 } else {
12125 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12126 }
12127 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12128 static int maxmessage_deprecate = 0;
12129 if (maxmessage_deprecate == 0) {
12130 maxmessage_deprecate = 1;
12131 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12132 }
12133 if (sscanf(val, "%30d", &x) == 1) {
12134 vmmaxsecs = x;
12135 } else {
12136 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12137 }
12138 }
12139
12140 vmminsecs = 0;
12141 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
12142 if (sscanf(val, "%30d", &x) == 1) {
12143 vmminsecs = x;
12144 if (maxsilence / 1000 >= vmminsecs) {
12145 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
12146 }
12147 } else {
12148 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12149 }
12150 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12151 static int maxmessage_deprecate = 0;
12152 if (maxmessage_deprecate == 0) {
12153 maxmessage_deprecate = 1;
12154 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12155 }
12156 if (sscanf(val, "%30d", &x) == 1) {
12157 vmminsecs = x;
12158 if (maxsilence / 1000 >= vmminsecs) {
12159 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12160 }
12161 } else {
12162 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12163 }
12164 }
12165
12166 val = ast_variable_retrieve(cfg, "general", "format");
12167 if (!val) {
12168 val = "wav";
12169 } else {
12170 tmp = ast_strdupa(val);
12171 val = ast_format_str_reduce(tmp);
12172 if (!val) {
12173 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12174 val = "wav";
12175 }
12176 }
12177 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12178
12179 skipms = 3000;
12180 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12181 if (sscanf(val, "%30d", &x) == 1) {
12182 maxgreet = x;
12183 } else {
12184 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12185 }
12186 }
12187
12188 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12189 if (sscanf(val, "%30d", &x) == 1) {
12190 skipms = x;
12191 } else {
12192 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12193 }
12194 }
12195
12196 maxlogins = 3;
12197 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12198 if (sscanf(val, "%30d", &x) == 1) {
12199 maxlogins = x;
12200 } else {
12201 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12202 }
12203 }
12204
12205 minpassword = MINPASSWORD;
12206 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12207 if (sscanf(val, "%30d", &x) == 1) {
12208 minpassword = x;
12209 } else {
12210 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12211 }
12212 }
12213
12214
12215 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12216 val = "no";
12217 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12218
12219
12220 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12221 val = "no";
12222 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12223
12224 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12225 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12226 stringp = ast_strdupa(val);
12227 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12228 if (!ast_strlen_zero(stringp)) {
12229 q = strsep(&stringp, ",");
12230 while ((*q == ' ')||(*q == '\t'))
12231 q++;
12232 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12233 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12234 } else {
12235 cidinternalcontexts[x][0] = '\0';
12236 }
12237 }
12238 }
12239 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12240 ast_debug(1, "VM Review Option disabled globally\n");
12241 val = "no";
12242 }
12243 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12244
12245
12246 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12247 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12248 val = "no";
12249 } else {
12250 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12251 }
12252 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12253 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12254 ast_debug(1, "VM next message wrap disabled globally\n");
12255 val = "no";
12256 }
12257 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12258
12259 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12260 ast_debug(1, "VM Operator break disabled globally\n");
12261 val = "no";
12262 }
12263 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12264
12265 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12266 ast_debug(1, "VM CID Info before msg disabled globally\n");
12267 val = "no";
12268 }
12269 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12270
12271 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12272 ast_debug(1, "Send Voicemail msg disabled globally\n");
12273 val = "no";
12274 }
12275 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12276
12277 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12278 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12279 val = "yes";
12280 }
12281 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12282
12283 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12284 ast_debug(1, "Move Heard enabled globally\n");
12285 val = "yes";
12286 }
12287 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12288
12289 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12290 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12291 val = "no";
12292 }
12293 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12294
12295 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12296 ast_debug(1, "Duration info before msg enabled globally\n");
12297 val = "yes";
12298 }
12299 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12300
12301 saydurationminfo = 2;
12302 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12303 if (sscanf(val, "%30d", &x) == 1) {
12304 saydurationminfo = x;
12305 } else {
12306 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12307 }
12308 }
12309
12310 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12311 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12312 val = "no";
12313 }
12314 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12315
12316 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12317 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12318 ast_debug(1, "found dialout context: %s\n", dialcontext);
12319 } else {
12320 dialcontext[0] = '\0';
12321 }
12322
12323 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12324 ast_copy_string(callcontext, val, sizeof(callcontext));
12325 ast_debug(1, "found callback context: %s\n", callcontext);
12326 } else {
12327 callcontext[0] = '\0';
12328 }
12329
12330 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12331 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12332 ast_debug(1, "found operator context: %s\n", exitcontext);
12333 } else {
12334 exitcontext[0] = '\0';
12335 }
12336
12337
12338 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12339 ast_copy_string(vm_password, val, sizeof(vm_password));
12340 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12341 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12342 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12343 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12344 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12345 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12346 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12347 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12348 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12349 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12350 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12351 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12352 }
12353 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12354 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12355 }
12356
12357 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12358 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12359 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12360 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12361 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12362 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12363 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12364 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12365 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12366 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12367
12368 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12369 val = "no";
12370 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12371
12372 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12373 val = "voicemail.conf";
12374 }
12375 if (!(strcmp(val, "spooldir"))) {
12376 passwordlocation = OPT_PWLOC_SPOOLDIR;
12377 } else {
12378 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12379 }
12380
12381 poll_freq = DEFAULT_POLL_FREQ;
12382 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12383 if (sscanf(val, "%30u", &poll_freq) != 1) {
12384 poll_freq = DEFAULT_POLL_FREQ;
12385 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12386 }
12387 }
12388
12389 poll_mailboxes = 0;
12390 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12391 poll_mailboxes = ast_true(val);
12392
12393 memset(fromstring, 0, sizeof(fromstring));
12394 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12395 strcpy(charset, "ISO-8859-1");
12396 if (emailbody) {
12397 ast_free(emailbody);
12398 emailbody = NULL;
12399 }
12400 if (emailsubject) {
12401 ast_free(emailsubject);
12402 emailsubject = NULL;
12403 }
12404 if (pagerbody) {
12405 ast_free(pagerbody);
12406 pagerbody = NULL;
12407 }
12408 if (pagersubject) {
12409 ast_free(pagersubject);
12410 pagersubject = NULL;
12411 }
12412 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12413 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12414 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12415 ast_copy_string(fromstring, val, sizeof(fromstring));
12416 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12417 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12418 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12419 ast_copy_string(charset, val, sizeof(charset));
12420 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12421 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12422 for (x = 0; x < 4; x++) {
12423 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12424 }
12425 }
12426 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12427 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12428 for (x = 0; x < 4; x++) {
12429 memcpy(&adsisec[x], &tmpadsi[x], 1);
12430 }
12431 }
12432 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12433 if (atoi(val)) {
12434 adsiver = atoi(val);
12435 }
12436 }
12437 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12438 ast_copy_string(zonetag, val, sizeof(zonetag));
12439 }
12440 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12441 ast_copy_string(locale, val, sizeof(locale));
12442 }
12443 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12444 emailsubject = ast_strdup(substitute_escapes(val));
12445 }
12446 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12447 emailbody = ast_strdup(substitute_escapes(val));
12448 }
12449 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12450 pagersubject = ast_strdup(substitute_escapes(val));
12451 }
12452 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12453 pagerbody = ast_strdup(substitute_escapes(val));
12454 }
12455
12456
12457 if (ucfg) {
12458 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12459 if (!strcasecmp(cat, "general")) {
12460 continue;
12461 }
12462 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12463 continue;
12464 if ((current = find_or_create(userscontext, cat))) {
12465 populate_defaults(current);
12466 apply_options_full(current, ast_variable_browse(ucfg, cat));
12467 ast_copy_string(current->context, userscontext, sizeof(current->context));
12468 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12469 current->passwordlocation = OPT_PWLOC_USERSCONF;
12470 }
12471
12472 switch (current->passwordlocation) {
12473 case OPT_PWLOC_SPOOLDIR:
12474 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12475 read_password_from_file(secretfn, current->password, sizeof(current->password));
12476 }
12477 }
12478 }
12479 }
12480
12481
12482 cat = ast_category_browse(cfg, NULL);
12483 while (cat) {
12484 if (strcasecmp(cat, "general")) {
12485 var = ast_variable_browse(cfg, cat);
12486 if (strcasecmp(cat, "zonemessages")) {
12487
12488 while (var) {
12489 append_mailbox(cat, var->name, var->value);
12490 var = var->next;
12491 }
12492 } else {
12493
12494 while (var) {
12495 struct vm_zone *z;
12496 if ((z = ast_malloc(sizeof(*z)))) {
12497 char *msg_format, *tzone;
12498 msg_format = ast_strdupa(var->value);
12499 tzone = strsep(&msg_format, "|,");
12500 if (msg_format) {
12501 ast_copy_string(z->name, var->name, sizeof(z->name));
12502 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12503 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12504 AST_LIST_LOCK(&zones);
12505 AST_LIST_INSERT_HEAD(&zones, z, list);
12506 AST_LIST_UNLOCK(&zones);
12507 } else {
12508 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12509 ast_free(z);
12510 }
12511 } else {
12512 AST_LIST_UNLOCK(&users);
12513 return -1;
12514 }
12515 var = var->next;
12516 }
12517 }
12518 }
12519 cat = ast_category_browse(cfg, cat);
12520 }
12521
12522 AST_LIST_UNLOCK(&users);
12523
12524 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12525 start_poll_thread();
12526 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12527 stop_poll_thread();;
12528
12529 return 0;
12530 } else {
12531 AST_LIST_UNLOCK(&users);
12532 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12533 return 0;
12534 }
12535 }
12536
12537 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12538 {
12539 int res = -1;
12540 char dir[PATH_MAX];
12541 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12542 ast_debug(2, "About to try retrieving name file %s\n", dir);
12543 RETRIEVE(dir, -1, mailbox, context);
12544 if (ast_fileexists(dir, NULL, NULL)) {
12545 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12546 }
12547 DISPOSE(dir, -1);
12548 return res;
12549 }
12550
12551 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12552 struct ast_config *pwconf;
12553 struct ast_flags config_flags = { 0 };
12554
12555 pwconf = ast_config_load(secretfn, config_flags);
12556 if (pwconf) {
12557 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12558 if (val) {
12559 ast_copy_string(password, val, passwordlen);
12560 ast_config_destroy(pwconf);
12561 return;
12562 }
12563 ast_config_destroy(pwconf);
12564 }
12565 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12566 }
12567
12568 static int write_password_to_file(const char *secretfn, const char *password) {
12569 struct ast_config *conf;
12570 struct ast_category *cat;
12571 struct ast_variable *var;
12572 int res = -1;
12573
12574 if (!(conf = ast_config_new())) {
12575 ast_log(LOG_ERROR, "Error creating new config structure\n");
12576 return res;
12577 }
12578 if (!(cat = ast_category_new("general", "", 1))) {
12579 ast_log(LOG_ERROR, "Error creating new category structure\n");
12580 ast_config_destroy(conf);
12581 return res;
12582 }
12583 if (!(var = ast_variable_new("password", password, ""))) {
12584 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12585 ast_config_destroy(conf);
12586 ast_category_destroy(cat);
12587 return res;
12588 }
12589 ast_category_append(conf, cat);
12590 ast_variable_append(cat, var);
12591 if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12592 res = 0;
12593 } else {
12594 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12595 }
12596
12597 ast_config_destroy(conf);
12598 return res;
12599 }
12600
12601 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12602 {
12603 char *context;
12604 char *args_copy;
12605 int res;
12606
12607 if (ast_strlen_zero(data)) {
12608 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context\n");
12609 return -1;
12610 }
12611
12612 args_copy = ast_strdupa(data);
12613 if ((context = strchr(args_copy, '@'))) {
12614 *context++ = '\0';
12615 } else {
12616 context = "default";
12617 }
12618
12619 if ((res = sayname(chan, args_copy, context) < 0)) {
12620 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12621 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12622 if (!res) {
12623 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12624 }
12625 }
12626
12627 return res;
12628 }
12629
12630 #ifdef TEST_FRAMEWORK
12631 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12632 {
12633 return 0;
12634 }
12635
12636 static struct ast_frame *fake_read(struct ast_channel *ast)
12637 {
12638 return &ast_null_frame;
12639 }
12640
12641 AST_TEST_DEFINE(test_voicemail_vmsayname)
12642 {
12643 char dir[PATH_MAX];
12644 char dir2[PATH_MAX];
12645 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12646 static const char TEST_EXTENSION[] = "1234";
12647
12648 struct ast_channel *test_channel1 = NULL;
12649 int res = -1;
12650
12651 static const struct ast_channel_tech fake_tech = {
12652 .write = fake_write,
12653 .read = fake_read,
12654 };
12655
12656 switch (cmd) {
12657 case TEST_INIT:
12658 info->name = "vmsayname_exec";
12659 info->category = "/apps/app_voicemail/";
12660 info->summary = "Vmsayname unit test";
12661 info->description =
12662 "This tests passing various parameters to vmsayname";
12663 return AST_TEST_NOT_RUN;
12664 case TEST_EXECUTE:
12665 break;
12666 }
12667
12668 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12669 NULL, NULL, 0, 0, "TestChannel1"))) {
12670 goto exit_vmsayname_test;
12671 }
12672
12673
12674 test_channel1->nativeformats = AST_FORMAT_GSM;
12675 test_channel1->writeformat = AST_FORMAT_GSM;
12676 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12677 test_channel1->readformat = AST_FORMAT_GSM;
12678 test_channel1->rawreadformat = AST_FORMAT_GSM;
12679 test_channel1->tech = &fake_tech;
12680
12681 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12682 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12683 if (!(res = vmsayname_exec(test_channel1, dir))) {
12684 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12685 if (ast_fileexists(dir, NULL, NULL)) {
12686 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12687 res = -1;
12688 goto exit_vmsayname_test;
12689 } else {
12690
12691 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12692 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12693 goto exit_vmsayname_test;
12694 }
12695 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12696 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12697
12698 if ((res = symlink(dir, dir2))) {
12699 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12700 goto exit_vmsayname_test;
12701 }
12702 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12703 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12704 res = vmsayname_exec(test_channel1, dir);
12705
12706
12707 unlink(dir2);
12708 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12709 rmdir(dir2);
12710 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12711 rmdir(dir2);
12712 }
12713 }
12714
12715 exit_vmsayname_test:
12716
12717 if (test_channel1) {
12718 ast_hangup(test_channel1);
12719 }
12720
12721 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12722 }
12723
12724 AST_TEST_DEFINE(test_voicemail_msgcount)
12725 {
12726 int i, j, res = AST_TEST_PASS, syserr;
12727 struct ast_vm_user *vmu;
12728 struct vm_state vms;
12729 #ifdef IMAP_STORAGE
12730 struct ast_channel *chan = NULL;
12731 #endif
12732 struct {
12733 char dir[256];
12734 char file[256];
12735 char txtfile[256];
12736 } tmp[3];
12737 char syscmd[256];
12738 const char origweasels[] = "tt-weasels";
12739 const char testcontext[] = "test";
12740 const char testmailbox[] = "00000000";
12741 const char testspec[] = "00000000@test";
12742 FILE *txt;
12743 int new, old, urgent;
12744 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12745 const int folder2mbox[3] = { 1, 11, 0 };
12746 const int expected_results[3][12] = {
12747
12748 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12749 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12750 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12751 };
12752
12753 switch (cmd) {
12754 case TEST_INIT:
12755 info->name = "test_voicemail_msgcount";
12756 info->category = "/apps/app_voicemail/";
12757 info->summary = "Test Voicemail status checks";
12758 info->description =
12759 "Verify that message counts are correct when retrieved through the public API";
12760 return AST_TEST_NOT_RUN;
12761 case TEST_EXECUTE:
12762 break;
12763 }
12764
12765
12766 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12767 if ((syserr = ast_safe_system(syscmd))) {
12768 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12769 syserr > 0 ? strerror(syserr) : "unable to fork()");
12770 return AST_TEST_FAIL;
12771 }
12772
12773 #ifdef IMAP_STORAGE
12774 if (!(chan = ast_dummy_channel_alloc())) {
12775 ast_test_status_update(test, "Unable to create dummy channel\n");
12776 return AST_TEST_FAIL;
12777 }
12778 #endif
12779
12780 if (!(vmu = find_user(NULL, testcontext, testmailbox)) &&
12781 !(vmu = find_or_create(testcontext, testmailbox))) {
12782 ast_test_status_update(test, "Cannot create vmu structure\n");
12783 ast_unreplace_sigchld();
12784 #ifdef IMAP_STORAGE
12785 chan = ast_channel_unref(chan);
12786 #endif
12787 return AST_TEST_FAIL;
12788 }
12789
12790 populate_defaults(vmu);
12791 memset(&vms, 0, sizeof(vms));
12792
12793
12794 for (i = 0; i < 3; i++) {
12795 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12796 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12797 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12798
12799 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12800 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12801 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12802 if ((syserr = ast_safe_system(syscmd))) {
12803 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12804 syserr > 0 ? strerror(syserr) : "unable to fork()");
12805 ast_unreplace_sigchld();
12806 #ifdef IMAP_STORAGE
12807 chan = ast_channel_unref(chan);
12808 #endif
12809 return AST_TEST_FAIL;
12810 }
12811 }
12812
12813 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12814 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12815 fclose(txt);
12816 } else {
12817 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12818 res = AST_TEST_FAIL;
12819 break;
12820 }
12821 open_mailbox(&vms, vmu, folder2mbox[i]);
12822 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12823
12824
12825 for (j = 0; j < 3; j++) {
12826
12827 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12828 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12829 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12830 res = AST_TEST_FAIL;
12831 }
12832 }
12833
12834 new = old = urgent = 0;
12835 if (ast_app_inboxcount(testspec, &new, &old)) {
12836 ast_test_status_update(test, "inboxcount returned failure\n");
12837 res = AST_TEST_FAIL;
12838 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12839 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12840 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12841 res = AST_TEST_FAIL;
12842 }
12843
12844 new = old = urgent = 0;
12845 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12846 ast_test_status_update(test, "inboxcount2 returned failure\n");
12847 res = AST_TEST_FAIL;
12848 } else if (old != expected_results[i][6 + 0] ||
12849 urgent != expected_results[i][6 + 1] ||
12850 new != expected_results[i][6 + 2] ) {
12851 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12852 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12853 res = AST_TEST_FAIL;
12854 }
12855
12856 new = old = urgent = 0;
12857 for (j = 0; j < 3; j++) {
12858 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12859 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12860 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12861 res = AST_TEST_FAIL;
12862 }
12863 }
12864 }
12865
12866 for (i = 0; i < 3; i++) {
12867
12868
12869
12870 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12871 DISPOSE(tmp[i].dir, 0);
12872 }
12873
12874 if (vms.deleted) {
12875 ast_free(vms.deleted);
12876 }
12877 if (vms.heard) {
12878 ast_free(vms.heard);
12879 }
12880
12881 #ifdef IMAP_STORAGE
12882 chan = ast_channel_unref(chan);
12883 #endif
12884
12885
12886 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12887 if ((syserr = ast_safe_system(syscmd))) {
12888 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12889 syserr > 0 ? strerror(syserr) : "unable to fork()");
12890 }
12891
12892 return res;
12893 }
12894
12895 AST_TEST_DEFINE(test_voicemail_notify_endl)
12896 {
12897 int res = AST_TEST_PASS;
12898 char testcontext[] = "test";
12899 char testmailbox[] = "00000000";
12900 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12901 char attach[256], attach2[256];
12902 char buf[256] = "";
12903 struct ast_channel *chan = NULL;
12904 struct ast_vm_user *vmu, vmus = {
12905 .flags = 0,
12906 };
12907 FILE *file;
12908 struct {
12909 char *name;
12910 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12911 void *location;
12912 union {
12913 int intval;
12914 char *strval;
12915 } u;
12916 } test_items[] = {
12917 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12918 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12919 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12920 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12921 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12922 { "attach2", STRPTR, attach2, .u.strval = "" },
12923 { "attach", STRPTR, attach, .u.strval = "" },
12924 };
12925 int which;
12926
12927 switch (cmd) {
12928 case TEST_INIT:
12929 info->name = "test_voicemail_notify_endl";
12930 info->category = "/apps/app_voicemail/";
12931 info->summary = "Test Voicemail notification end-of-line";
12932 info->description =
12933 "Verify that notification emails use a consistent end-of-line character";
12934 return AST_TEST_NOT_RUN;
12935 case TEST_EXECUTE:
12936 break;
12937 }
12938
12939 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12940 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12941
12942 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12943 !(vmu = find_or_create(testcontext, testmailbox))) {
12944 ast_test_status_update(test, "Cannot create vmu structure\n");
12945 return AST_TEST_NOT_RUN;
12946 }
12947
12948 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12949 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12950 return AST_TEST_NOT_RUN;
12951 }
12952
12953 populate_defaults(vmu);
12954 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12955 #ifdef IMAP_STORAGE
12956
12957 #endif
12958
12959 file = tmpfile();
12960 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12961
12962 rewind(file);
12963 if (ftruncate(fileno(file), 0)) {
12964 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12965 res = AST_TEST_FAIL;
12966 break;
12967 }
12968
12969
12970 if (test_items[which].type == INT) {
12971 *((int *) test_items[which].location) = test_items[which].u.intval;
12972 } else if (test_items[which].type == FLAGVAL) {
12973 if (ast_test_flag(vmu, test_items[which].u.intval)) {
12974 ast_clear_flag(vmu, test_items[which].u.intval);
12975 } else {
12976 ast_set_flag(vmu, test_items[which].u.intval);
12977 }
12978 } else if (test_items[which].type == STATIC) {
12979 strcpy(test_items[which].location, test_items[which].u.strval);
12980 } else if (test_items[which].type == STRPTR) {
12981 test_items[which].location = test_items[which].u.strval;
12982 }
12983
12984 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
12985 rewind(file);
12986 while (fgets(buf, sizeof(buf), file)) {
12987 if (
12988 #ifdef IMAP_STORAGE
12989 buf[strlen(buf) - 2] != '\r'
12990 #else
12991 buf[strlen(buf) - 2] == '\r'
12992 #endif
12993 || buf[strlen(buf) - 1] != '\n') {
12994 res = AST_TEST_FAIL;
12995 }
12996 }
12997 }
12998 fclose(file);
12999 return res;
13000 }
13001
13002 AST_TEST_DEFINE(test_voicemail_load_config)
13003 {
13004 int res = AST_TEST_PASS;
13005 struct ast_vm_user *vmu;
13006 struct ast_config *cfg;
13007 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
13008 int fd;
13009 FILE *file;
13010 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
13011
13012 switch (cmd) {
13013 case TEST_INIT:
13014 info->name = "test_voicemail_load_config";
13015 info->category = "/apps/app_voicemail/";
13016 info->summary = "Test loading Voicemail config";
13017 info->description =
13018 "Verify that configuration is loaded consistently. "
13019 "This is to test regressions of ASTERISK-18838 where it was noticed that "
13020 "some options were loaded after the mailboxes were instantiated, causing "
13021 "those options not to be set correctly.";
13022 return AST_TEST_NOT_RUN;
13023 case TEST_EXECUTE:
13024 break;
13025 }
13026
13027
13028 if ((fd = mkstemp(config_filename)) < 0) {
13029 return AST_TEST_FAIL;
13030 }
13031 if (!(file = fdopen(fd, "w"))) {
13032 close(fd);
13033 unlink(config_filename);
13034 return AST_TEST_FAIL;
13035 }
13036 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
13037 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
13038 fputs("00000002 => 9999,Mrs. Test\n", file);
13039 fclose(file);
13040
13041 if (!(cfg = ast_config_load(config_filename, config_flags))) {
13042 res = AST_TEST_FAIL;
13043 goto cleanup;
13044 }
13045
13046 load_config_from_memory(1, cfg, NULL);
13047 ast_config_destroy(cfg);
13048
13049 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
13050 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
13051 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
13052
13053 AST_LIST_LOCK(&users);
13054 AST_LIST_TRAVERSE(&users, vmu, list) {
13055 if (!strcmp(vmu->mailbox, "00000001")) {
13056 if (0);
13057 CHECK(vmu, callback, "othercontext")
13058 CHECK(vmu, locale, "nl_NL.UTF-8")
13059 CHECK(vmu, zonetag, "central")
13060 } else if (!strcmp(vmu->mailbox, "00000002")) {
13061 if (0);
13062 CHECK(vmu, callback, "somecontext")
13063 CHECK(vmu, locale, "de_DE.UTF-8")
13064 CHECK(vmu, zonetag, "european")
13065 }
13066 }
13067 AST_LIST_UNLOCK(&users);
13068
13069 #undef CHECK
13070
13071
13072 load_config(1);
13073
13074 cleanup:
13075 unlink(config_filename);
13076 return res;
13077 }
13078
13079 #endif
13080
13081 static int reload(void)
13082 {
13083 return load_config(1);
13084 }
13085
13086 static int unload_module(void)
13087 {
13088 int res;
13089
13090 res = ast_unregister_application(app);
13091 res |= ast_unregister_application(app2);
13092 res |= ast_unregister_application(app3);
13093 res |= ast_unregister_application(app4);
13094 res |= ast_unregister_application(sayname_app);
13095 res |= ast_custom_function_unregister(&mailbox_exists_acf);
13096 res |= ast_manager_unregister("VoicemailUsersList");
13097 res |= ast_data_unregister(NULL);
13098 #ifdef TEST_FRAMEWORK
13099 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
13100 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
13101 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
13102 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
13103 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
13104 #endif
13105 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13106 ast_uninstall_vm_functions();
13107 ao2_ref(inprocess_container, -1);
13108
13109 if (poll_thread != AST_PTHREADT_NULL)
13110 stop_poll_thread();
13111
13112 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
13113 ast_unload_realtime("voicemail");
13114 ast_unload_realtime("voicemail_data");
13115
13116 free_vm_users();
13117 free_vm_zones();
13118 return res;
13119 }
13120
13121 static int load_module(void)
13122 {
13123 int res;
13124 my_umask = umask(0);
13125 umask(my_umask);
13126
13127 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
13128 return AST_MODULE_LOAD_DECLINE;
13129 }
13130
13131
13132 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
13133
13134 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
13135 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
13136 }
13137
13138 if ((res = load_config(0)))
13139 return res;
13140
13141 res = ast_register_application_xml(app, vm_exec);
13142 res |= ast_register_application_xml(app2, vm_execmain);
13143 res |= ast_register_application_xml(app3, vm_box_exists);
13144 res |= ast_register_application_xml(app4, vmauthenticate);
13145 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
13146 res |= ast_custom_function_register(&mailbox_exists_acf);
13147 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
13148 #ifdef TEST_FRAMEWORK
13149 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
13150 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
13151 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
13152 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
13153 res |= AST_TEST_REGISTER(test_voicemail_load_config);
13154 #endif
13155
13156 if (res)
13157 return res;
13158
13159 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13160 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
13161
13162 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
13163 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
13164 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
13165
13166 return res;
13167 }
13168
13169 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13170 {
13171 int cmd = 0;
13172 char destination[80] = "";
13173 int retries = 0;
13174
13175 if (!num) {
13176 ast_verb(3, "Destination number will be entered manually\n");
13177 while (retries < 3 && cmd != 't') {
13178 destination[1] = '\0';
13179 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13180 if (!cmd)
13181 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13182 if (!cmd)
13183 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13184 if (!cmd) {
13185 cmd = ast_waitfordigit(chan, 6000);
13186 if (cmd)
13187 destination[0] = cmd;
13188 }
13189 if (!cmd) {
13190 retries++;
13191 } else {
13192
13193 if (cmd < 0)
13194 return 0;
13195 if (cmd == '*') {
13196 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13197 return 0;
13198 }
13199 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13200 retries++;
13201 else
13202 cmd = 't';
13203 }
13204 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13205 }
13206 if (retries >= 3) {
13207 return 0;
13208 }
13209
13210 } else {
13211 if (option_verbose > 2)
13212 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
13213 ast_copy_string(destination, num, sizeof(destination));
13214 }
13215
13216 if (!ast_strlen_zero(destination)) {
13217 if (destination[strlen(destination) -1 ] == '*')
13218 return 0;
13219 if (option_verbose > 2)
13220 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13221 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13222 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13223 chan->priority = 0;
13224 return 9;
13225 }
13226 return 0;
13227 }
13228
13229
13230
13231
13232
13233
13234
13235
13236
13237
13238
13239
13240
13241
13242 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)
13243 {
13244 int res = 0;
13245 char filename[PATH_MAX];
13246 struct ast_config *msg_cfg = NULL;
13247 const char *origtime, *context;
13248 char *name, *num;
13249 int retries = 0;
13250 char *cid;
13251 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13252
13253 vms->starting = 0;
13254
13255 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13256
13257
13258 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13259 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13260 msg_cfg = ast_config_load(filename, config_flags);
13261 DISPOSE(vms->curdir, vms->curmsg);
13262 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
13263 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13264 return 0;
13265 }
13266
13267 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13268 ast_config_destroy(msg_cfg);
13269 return 0;
13270 }
13271
13272 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13273
13274 context = ast_variable_retrieve(msg_cfg, "message", "context");
13275 if (!strncasecmp("macro", context, 5))
13276 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13277 switch (option) {
13278 case 3:
13279 if (!res)
13280 res = play_message_datetime(chan, vmu, origtime, filename);
13281 if (!res)
13282 res = play_message_callerid(chan, vms, cid, context, 0);
13283
13284 res = 't';
13285 break;
13286
13287 case 2:
13288
13289 if (ast_strlen_zero(cid))
13290 break;
13291
13292 ast_callerid_parse(cid, &name, &num);
13293 while ((res > -1) && (res != 't')) {
13294 switch (res) {
13295 case '1':
13296 if (num) {
13297
13298 res = dialout(chan, vmu, num, vmu->callback);
13299 if (res) {
13300 ast_config_destroy(msg_cfg);
13301 return 9;
13302 }
13303 } else {
13304 res = '2';
13305 }
13306 break;
13307
13308 case '2':
13309
13310 if (!ast_strlen_zero(vmu->dialout)) {
13311 res = dialout(chan, vmu, NULL, vmu->dialout);
13312 if (res) {
13313 ast_config_destroy(msg_cfg);
13314 return 9;
13315 }
13316 } else {
13317 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13318 res = ast_play_and_wait(chan, "vm-sorry");
13319 }
13320 ast_config_destroy(msg_cfg);
13321 return res;
13322 case '*':
13323 res = 't';
13324 break;
13325 case '3':
13326 case '4':
13327 case '5':
13328 case '6':
13329 case '7':
13330 case '8':
13331 case '9':
13332 case '0':
13333
13334 res = ast_play_and_wait(chan, "vm-sorry");
13335 retries++;
13336 break;
13337 default:
13338 if (num) {
13339 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13340 res = ast_play_and_wait(chan, "vm-num-i-have");
13341 if (!res)
13342 res = play_message_callerid(chan, vms, num, vmu->context, 1);
13343 if (!res)
13344 res = ast_play_and_wait(chan, "vm-tocallnum");
13345
13346 if (!ast_strlen_zero(vmu->dialout)) {
13347 if (!res)
13348 res = ast_play_and_wait(chan, "vm-calldiffnum");
13349 }
13350 } else {
13351 res = ast_play_and_wait(chan, "vm-nonumber");
13352 if (!ast_strlen_zero(vmu->dialout)) {
13353 if (!res)
13354 res = ast_play_and_wait(chan, "vm-toenternumber");
13355 }
13356 }
13357 if (!res) {
13358 res = ast_play_and_wait(chan, "vm-star-cancel");
13359 }
13360 if (!res) {
13361 res = ast_waitfordigit(chan, 6000);
13362 }
13363 if (!res) {
13364 retries++;
13365 if (retries > 3) {
13366 res = 't';
13367 }
13368 }
13369 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13370 break;
13371
13372 }
13373 if (res == 't')
13374 res = 0;
13375 else if (res == '*')
13376 res = -1;
13377 }
13378 break;
13379
13380 case 1:
13381
13382 if (ast_strlen_zero(cid))
13383 break;
13384
13385 ast_callerid_parse(cid, &name, &num);
13386 if (!num) {
13387 ast_verb(3, "No CID number available, no reply sent\n");
13388 if (!res)
13389 res = ast_play_and_wait(chan, "vm-nonumber");
13390 ast_config_destroy(msg_cfg);
13391 return res;
13392 } else {
13393 struct ast_vm_user vmu2;
13394 if (find_user(&vmu2, vmu->context, num)) {
13395 struct leave_vm_options leave_options;
13396 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13397 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13398
13399 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13400
13401 memset(&leave_options, 0, sizeof(leave_options));
13402 leave_options.record_gain = record_gain;
13403 res = leave_voicemail(chan, mailbox, &leave_options);
13404 if (!res)
13405 res = 't';
13406 ast_config_destroy(msg_cfg);
13407 return res;
13408 } else {
13409
13410 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13411 ast_play_and_wait(chan, "vm-nobox");
13412 res = 't';
13413 ast_config_destroy(msg_cfg);
13414 return res;
13415 }
13416 }
13417 res = 0;
13418
13419 break;
13420 }
13421
13422 #ifndef IMAP_STORAGE
13423 ast_config_destroy(msg_cfg);
13424
13425 if (!res) {
13426 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13427 vms->heard[msg] = 1;
13428 res = wait_file(chan, vms, vms->fn);
13429 }
13430 #endif
13431 return res;
13432 }
13433
13434 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13435 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
13436 signed char record_gain, struct vm_state *vms, char *flag)
13437 {
13438
13439 int res = 0;
13440 int cmd = 0;
13441 int max_attempts = 3;
13442 int attempts = 0;
13443 int recorded = 0;
13444 int msg_exists = 0;
13445 signed char zero_gain = 0;
13446 char tempfile[PATH_MAX];
13447 char *acceptdtmf = "#";
13448 char *canceldtmf = "";
13449 int canceleddtmf = 0;
13450
13451
13452
13453
13454 if (duration == NULL) {
13455 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13456 return -1;
13457 }
13458
13459 if (!outsidecaller)
13460 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13461 else
13462 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13463
13464 cmd = '3';
13465
13466 while ((cmd >= 0) && (cmd != 't')) {
13467 switch (cmd) {
13468 case '1':
13469 if (!msg_exists) {
13470
13471 cmd = '3';
13472 break;
13473 } else {
13474
13475 ast_verb(3, "Saving message as is\n");
13476 if (!outsidecaller)
13477 ast_filerename(tempfile, recordfile, NULL);
13478 ast_stream_and_wait(chan, "vm-msgsaved", "");
13479 if (!outsidecaller) {
13480
13481 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13482 DISPOSE(recordfile, -1);
13483 }
13484 cmd = 't';
13485 return res;
13486 }
13487 case '2':
13488
13489 ast_verb(3, "Reviewing the message\n");
13490 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13491 break;
13492 case '3':
13493 msg_exists = 0;
13494
13495 if (recorded == 1)
13496 ast_verb(3, "Re-recording the message\n");
13497 else
13498 ast_verb(3, "Recording the message\n");
13499
13500 if (recorded && outsidecaller) {
13501 cmd = ast_play_and_wait(chan, INTRO);
13502 cmd = ast_play_and_wait(chan, "beep");
13503 }
13504 recorded = 1;
13505
13506 if (record_gain)
13507 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13508 if (ast_test_flag(vmu, VM_OPERATOR))
13509 canceldtmf = "0";
13510 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13511 if (strchr(canceldtmf, cmd)) {
13512
13513 canceleddtmf = 1;
13514 }
13515 if (record_gain)
13516 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13517 if (cmd == -1) {
13518
13519 if (!outsidecaller) {
13520
13521 ast_filedelete(tempfile, NULL);
13522 }
13523 return cmd;
13524 }
13525 if (cmd == '0') {
13526 break;
13527 } else if (cmd == '*') {
13528 break;
13529 #if 0
13530 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13531
13532 ast_verb(3, "Message too short\n");
13533 cmd = ast_play_and_wait(chan, "vm-tooshort");
13534 cmd = ast_filedelete(tempfile, NULL);
13535 break;
13536 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13537
13538 ast_verb(3, "Nothing recorded\n");
13539 cmd = ast_filedelete(tempfile, NULL);
13540 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13541 if (!cmd)
13542 cmd = ast_play_and_wait(chan, "vm-speakup");
13543 break;
13544 #endif
13545 } else {
13546
13547 msg_exists = 1;
13548 cmd = 0;
13549 }
13550 break;
13551 case '4':
13552 if (outsidecaller) {
13553
13554 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13555 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13556 res = ast_play_and_wait(chan, "vm-marked-urgent");
13557 strcpy(flag, "Urgent");
13558 } else if (flag) {
13559 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13560 res = ast_play_and_wait(chan, "vm-urgent-removed");
13561 strcpy(flag, "");
13562 } else {
13563 ast_play_and_wait(chan, "vm-sorry");
13564 }
13565 cmd = 0;
13566 } else {
13567 cmd = ast_play_and_wait(chan, "vm-sorry");
13568 }
13569 break;
13570 case '5':
13571 case '6':
13572 case '7':
13573 case '8':
13574 case '9':
13575 case '*':
13576 case '#':
13577 cmd = ast_play_and_wait(chan, "vm-sorry");
13578 break;
13579 #if 0
13580
13581
13582 case '*':
13583
13584 cmd = ast_play_and_wait(chan, "vm-deleted");
13585 cmd = ast_filedelete(tempfile, NULL);
13586 if (outsidecaller) {
13587 res = vm_exec(chan, NULL);
13588 return res;
13589 }
13590 else
13591 return 1;
13592 #endif
13593 case '0':
13594 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13595 cmd = ast_play_and_wait(chan, "vm-sorry");
13596 break;
13597 }
13598 if (msg_exists || recorded) {
13599 cmd = ast_play_and_wait(chan, "vm-saveoper");
13600 if (!cmd)
13601 cmd = ast_waitfordigit(chan, 3000);
13602 if (cmd == '1') {
13603 ast_filerename(tempfile, recordfile, NULL);
13604 ast_play_and_wait(chan, "vm-msgsaved");
13605 cmd = '0';
13606 } else if (cmd == '4') {
13607 if (flag) {
13608 ast_play_and_wait(chan, "vm-marked-urgent");
13609 strcpy(flag, "Urgent");
13610 }
13611 ast_play_and_wait(chan, "vm-msgsaved");
13612 cmd = '0';
13613 } else {
13614 ast_play_and_wait(chan, "vm-deleted");
13615 DELETE(tempfile, -1, tempfile, vmu);
13616 cmd = '0';
13617 }
13618 }
13619 return cmd;
13620 default:
13621
13622
13623
13624 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13625 return cmd;
13626 if (msg_exists) {
13627 cmd = ast_play_and_wait(chan, "vm-review");
13628 if (!cmd && outsidecaller) {
13629 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13630 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13631 } else if (flag) {
13632 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13633 }
13634 }
13635 } else {
13636 cmd = ast_play_and_wait(chan, "vm-torerecord");
13637 if (!cmd)
13638 cmd = ast_waitfordigit(chan, 600);
13639 }
13640
13641 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13642 cmd = ast_play_and_wait(chan, "vm-reachoper");
13643 if (!cmd)
13644 cmd = ast_waitfordigit(chan, 600);
13645 }
13646 #if 0
13647 if (!cmd)
13648 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13649 #endif
13650 if (!cmd)
13651 cmd = ast_waitfordigit(chan, 6000);
13652 if (!cmd) {
13653 attempts++;
13654 }
13655 if (attempts > max_attempts) {
13656 cmd = 't';
13657 }
13658 }
13659 }
13660 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13661
13662 ast_filedelete(tempfile, NULL);
13663 }
13664
13665 if (cmd != 't' && outsidecaller)
13666 ast_play_and_wait(chan, "vm-goodbye");
13667
13668 return cmd;
13669 }
13670
13671
13672
13673
13674
13675 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13676 .load = load_module,
13677 .unload = unload_module,
13678 .reload = reload,
13679 .nonoptreq = "res_adsi,res_smdi",
13680 );