00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073 #include "asterisk.h"
00074
00075 #ifdef IMAP_STORAGE
00076 #include <ctype.h>
00077 #include <signal.h>
00078 #include <pwd.h>
00079 #ifdef USE_SYSTEM_IMAP
00080 #include <imap/c-client.h>
00081 #include <imap/imap4r1.h>
00082 #include <imap/linkage.h>
00083 #elif defined (USE_SYSTEM_CCLIENT)
00084 #include <c-client/c-client.h>
00085 #include <c-client/imap4r1.h>
00086 #include <c-client/linkage.h>
00087 #else
00088 #include "c-client.h"
00089 #include "imap4r1.h"
00090 #include "linkage.h"
00091 #endif
00092 #endif
00093
00094 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 376262 $")
00095
00096 #include "asterisk/paths.h"
00097 #include <sys/time.h>
00098 #include <sys/stat.h>
00099 #include <sys/mman.h>
00100 #include <time.h>
00101 #include <dirent.h>
00102 #if defined(__FreeBSD__) || defined(__OpenBSD__)
00103 #include <sys/wait.h>
00104 #endif
00105
00106 #include "asterisk/logger.h"
00107 #include "asterisk/lock.h"
00108 #include "asterisk/file.h"
00109 #include "asterisk/channel.h"
00110 #include "asterisk/pbx.h"
00111 #include "asterisk/config.h"
00112 #include "asterisk/say.h"
00113 #include "asterisk/module.h"
00114 #include "asterisk/adsi.h"
00115 #include "asterisk/app.h"
00116 #include "asterisk/manager.h"
00117 #include "asterisk/dsp.h"
00118 #include "asterisk/localtime.h"
00119 #include "asterisk/cli.h"
00120 #include "asterisk/utils.h"
00121 #include "asterisk/stringfields.h"
00122 #include "asterisk/smdi.h"
00123 #include "asterisk/astobj2.h"
00124 #include "asterisk/event.h"
00125 #include "asterisk/taskprocessor.h"
00126 #include "asterisk/test.h"
00127
00128 #ifdef ODBC_STORAGE
00129 #include "asterisk/res_odbc.h"
00130 #endif
00131
00132 #ifdef IMAP_STORAGE
00133 #include "asterisk/threadstorage.h"
00134 #endif
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
00367
00368
00369
00370
00371
00372
00373
00374 #ifdef IMAP_STORAGE
00375 static char imapserver[48];
00376 static char imapport[8];
00377 static char imapflags[128];
00378 static char imapfolder[64];
00379 static char imapparentfolder[64] = "\0";
00380 static char greetingfolder[64];
00381 static char authuser[32];
00382 static char authpassword[42];
00383 static int imapversion = 1;
00384
00385 static int expungeonhangup = 1;
00386 static int imapgreetings = 0;
00387 static char delimiter = '\0';
00388
00389 struct vm_state;
00390 struct ast_vm_user;
00391
00392 AST_THREADSTORAGE(ts_vmstate);
00393
00394
00395 static int init_mailstream(struct vm_state *vms, int box);
00396 static void write_file(char *filename, char *buffer, unsigned long len);
00397 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00398 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00399 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00400 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00401 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00402 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00403 static void vmstate_insert(struct vm_state *vms);
00404 static void vmstate_delete(struct vm_state *vms);
00405 static void set_update(MAILSTREAM * stream);
00406 static void init_vm_state(struct vm_state *vms);
00407 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
00408 static void get_mailbox_delimiter(MAILSTREAM *stream);
00409 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00410 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00411 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);
00412 static void update_messages_by_imapuser(const char *user, unsigned long number);
00413 static int vm_delete(char *file);
00414
00415 static int imap_remove_file (char *dir, int msgnum);
00416 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00417 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00418 static void check_quota(struct vm_state *vms, char *mailbox);
00419 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00420 struct vmstate {
00421 struct vm_state *vms;
00422 AST_LIST_ENTRY(vmstate) list;
00423 };
00424
00425 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00426
00427 #endif
00428
00429 #define SMDI_MWI_WAIT_TIMEOUT 1000
00430
00431 #define COMMAND_TIMEOUT 5000
00432
00433 #define VOICEMAIL_DIR_MODE 0777
00434 #define VOICEMAIL_FILE_MODE 0666
00435 #define CHUNKSIZE 65536
00436
00437 #define VOICEMAIL_CONFIG "voicemail.conf"
00438 #define ASTERISK_USERNAME "asterisk"
00439
00440
00441
00442
00443 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00444 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00445 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00446 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00447 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00448 #define VALID_DTMF "1234567890*#"
00449
00450
00451
00452 #define SENDMAIL "/usr/sbin/sendmail -t"
00453
00454 #define INTRO "vm-intro"
00455
00456 #define MAXMSG 100
00457 #define MAXMSGLIMIT 9999
00458
00459 #define MINPASSWORD 0
00460
00461 #define BASELINELEN 72
00462 #define BASEMAXINLINE 256
00463 #ifdef IMAP_STORAGE
00464 #define ENDL "\r\n"
00465 #else
00466 #define ENDL "\n"
00467 #endif
00468
00469 #define MAX_DATETIME_FORMAT 512
00470 #define MAX_NUM_CID_CONTEXTS 10
00471
00472 #define VM_REVIEW (1 << 0)
00473 #define VM_OPERATOR (1 << 1)
00474 #define VM_SAYCID (1 << 2)
00475 #define VM_SVMAIL (1 << 3)
00476 #define VM_ENVELOPE (1 << 4)
00477 #define VM_SAYDURATION (1 << 5)
00478 #define VM_SKIPAFTERCMD (1 << 6)
00479 #define VM_FORCENAME (1 << 7)
00480 #define VM_FORCEGREET (1 << 8)
00481 #define VM_PBXSKIP (1 << 9)
00482 #define VM_DIRECFORWARD (1 << 10)
00483 #define VM_ATTACH (1 << 11)
00484 #define VM_DELETE (1 << 12)
00485 #define VM_ALLOCED (1 << 13)
00486 #define VM_SEARCH (1 << 14)
00487 #define VM_TEMPGREETWARN (1 << 15)
00488 #define VM_MOVEHEARD (1 << 16)
00489 #define VM_MESSAGEWRAP (1 << 17)
00490 #define VM_FWDURGAUTO (1 << 18)
00491 #define ERROR_LOCK_PATH -100
00492 #define OPERATOR_EXIT 300
00493
00494
00495 enum vm_box {
00496 NEW_FOLDER,
00497 OLD_FOLDER,
00498 WORK_FOLDER,
00499 FAMILY_FOLDER,
00500 FRIENDS_FOLDER,
00501 GREETINGS_FOLDER
00502 };
00503
00504 enum vm_option_flags {
00505 OPT_SILENT = (1 << 0),
00506 OPT_BUSY_GREETING = (1 << 1),
00507 OPT_UNAVAIL_GREETING = (1 << 2),
00508 OPT_RECORDGAIN = (1 << 3),
00509 OPT_PREPEND_MAILBOX = (1 << 4),
00510 OPT_AUTOPLAY = (1 << 6),
00511 OPT_DTMFEXIT = (1 << 7),
00512 OPT_MESSAGE_Urgent = (1 << 8),
00513 OPT_MESSAGE_PRIORITY = (1 << 9)
00514 };
00515
00516 enum vm_option_args {
00517 OPT_ARG_RECORDGAIN = 0,
00518 OPT_ARG_PLAYFOLDER = 1,
00519 OPT_ARG_DTMFEXIT = 2,
00520
00521 OPT_ARG_ARRAY_SIZE = 3,
00522 };
00523
00524 enum vm_passwordlocation {
00525 OPT_PWLOC_VOICEMAILCONF = 0,
00526 OPT_PWLOC_SPOOLDIR = 1,
00527 OPT_PWLOC_USERSCONF = 2,
00528 };
00529
00530 AST_APP_OPTIONS(vm_app_options, {
00531 AST_APP_OPTION('s', OPT_SILENT),
00532 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00533 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00534 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00535 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00536 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00537 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00538 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
00539 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
00540 });
00541
00542 static int load_config(int reload);
00543 #ifdef TEST_FRAMEWORK
00544 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00545 #endif
00546 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg);
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
00624
00625
00626
00627
00628
00629
00630
00631 struct baseio {
00632 int iocp;
00633 int iolen;
00634 int linelength;
00635 int ateof;
00636 unsigned char iobuf[BASEMAXINLINE];
00637 };
00638
00639
00640
00641 struct ast_vm_user {
00642 char context[AST_MAX_CONTEXT];
00643 char mailbox[AST_MAX_EXTENSION];
00644 char password[80];
00645 char fullname[80];
00646 char email[80];
00647 char *emailsubject;
00648 char *emailbody;
00649 char pager[80];
00650 char serveremail[80];
00651 char language[MAX_LANGUAGE];
00652 char zonetag[80];
00653 char locale[20];
00654 char callback[80];
00655 char dialout[80];
00656 char uniqueid[80];
00657 char exit[80];
00658 char attachfmt[20];
00659 unsigned int flags;
00660 int saydurationm;
00661 int minsecs;
00662 int maxmsg;
00663 int maxdeletedmsg;
00664 int maxsecs;
00665 int passwordlocation;
00666 #ifdef IMAP_STORAGE
00667 char imapuser[80];
00668 char imappassword[80];
00669 char imapfolder[64];
00670 char imapvmshareid[80];
00671 int imapversion;
00672 #endif
00673 double volgain;
00674 AST_LIST_ENTRY(ast_vm_user) list;
00675 };
00676
00677
00678 struct vm_zone {
00679 AST_LIST_ENTRY(vm_zone) list;
00680 char name[80];
00681 char timezone[80];
00682 char msg_format[512];
00683 };
00684
00685 #define VMSTATE_MAX_MSG_ARRAY 256
00686
00687
00688 struct vm_state {
00689 char curbox[80];
00690 char username[80];
00691 char context[80];
00692 char curdir[PATH_MAX];
00693 char vmbox[PATH_MAX];
00694 char fn[PATH_MAX];
00695 char intro[PATH_MAX];
00696 int *deleted;
00697 int *heard;
00698 int dh_arraysize;
00699 int curmsg;
00700 int lastmsg;
00701 int newmessages;
00702 int oldmessages;
00703 int urgentmessages;
00704 int starting;
00705 int repeats;
00706 #ifdef IMAP_STORAGE
00707 ast_mutex_t lock;
00708 int updated;
00709 long msgArray[VMSTATE_MAX_MSG_ARRAY];
00710 MAILSTREAM *mailstream;
00711 int vmArrayIndex;
00712 char imapuser[80];
00713 char imapfolder[64];
00714 int imapversion;
00715 int interactive;
00716 char introfn[PATH_MAX];
00717 unsigned int quota_limit;
00718 unsigned int quota_usage;
00719 struct vm_state *persist_vms;
00720 #endif
00721 };
00722
00723 #ifdef ODBC_STORAGE
00724 static char odbc_database[80];
00725 static char odbc_table[80];
00726 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00727 #define DISPOSE(a,b) remove_file(a,b)
00728 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
00729 #define EXISTS(a,b,c,d) (message_exists(a,b))
00730 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00731 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00732 #define DELETE(a,b,c,d) (delete_file(a,b))
00733 #else
00734 #ifdef IMAP_STORAGE
00735 #define DISPOSE(a,b) (imap_remove_file(a,b))
00736 #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))
00737 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00738 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00739 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00740 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00741 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00742 #else
00743 #define RETRIEVE(a,b,c,d)
00744 #define DISPOSE(a,b)
00745 #define STORE(a,b,c,d,e,f,g,h,i,j)
00746 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00747 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00748 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00749 #define DELETE(a,b,c,d) (vm_delete(c))
00750 #endif
00751 #endif
00752
00753 static char VM_SPOOL_DIR[PATH_MAX];
00754
00755 static char ext_pass_cmd[128];
00756 static char ext_pass_check_cmd[128];
00757
00758 static int my_umask;
00759
00760 #define PWDCHANGE_INTERNAL (1 << 1)
00761 #define PWDCHANGE_EXTERNAL (1 << 2)
00762 static int pwdchange = PWDCHANGE_INTERNAL;
00763
00764 #ifdef ODBC_STORAGE
00765 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00766 #else
00767 # ifdef IMAP_STORAGE
00768 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00769 # else
00770 # define tdesc "Comedian Mail (Voicemail System)"
00771 # endif
00772 #endif
00773
00774 static char userscontext[AST_MAX_EXTENSION] = "default";
00775
00776 static char *addesc = "Comedian Mail";
00777
00778
00779 static char *app = "VoiceMail";
00780
00781
00782 static char *app2 = "VoiceMailMain";
00783
00784 static char *app3 = "MailboxExists";
00785 static char *app4 = "VMAuthenticate";
00786
00787 static char *sayname_app = "VMSayName";
00788
00789 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00790 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00791 static char zonetag[80];
00792 static char locale[20];
00793 static int maxsilence;
00794 static int maxmsg;
00795 static int maxdeletedmsg;
00796 static int silencethreshold = 128;
00797 static char serveremail[80];
00798 static char mailcmd[160];
00799 static char externnotify[160];
00800 static struct ast_smdi_interface *smdi_iface = NULL;
00801 static char vmfmts[80];
00802 static double volgain;
00803 static int vmminsecs;
00804 static int vmmaxsecs;
00805 static int maxgreet;
00806 static int skipms;
00807 static int maxlogins;
00808 static int minpassword;
00809 static int passwordlocation;
00810
00811
00812
00813 static unsigned int poll_mailboxes;
00814
00815
00816 static unsigned int poll_freq;
00817
00818 #define DEFAULT_POLL_FREQ 30
00819
00820 AST_MUTEX_DEFINE_STATIC(poll_lock);
00821 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00822 static pthread_t poll_thread = AST_PTHREADT_NULL;
00823 static unsigned char poll_thread_run;
00824
00825
00826 static struct ast_event_sub *mwi_sub_sub;
00827
00828 static struct ast_event_sub *mwi_unsub_sub;
00829
00830
00831
00832
00833
00834
00835
00836
00837 struct mwi_sub {
00838 AST_RWLIST_ENTRY(mwi_sub) entry;
00839 int old_urgent;
00840 int old_new;
00841 int old_old;
00842 uint32_t uniqueid;
00843 char mailbox[1];
00844 };
00845
00846 struct mwi_sub_task {
00847 const char *mailbox;
00848 const char *context;
00849 uint32_t uniqueid;
00850 };
00851
00852 static struct ast_taskprocessor *mwi_subscription_tps;
00853
00854 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00855
00856
00857 static char listen_control_forward_key[12];
00858 static char listen_control_reverse_key[12];
00859 static char listen_control_pause_key[12];
00860 static char listen_control_restart_key[12];
00861 static char listen_control_stop_key[12];
00862
00863
00864 static char vm_password[80] = "vm-password";
00865 static char vm_newpassword[80] = "vm-newpassword";
00866 static char vm_passchanged[80] = "vm-passchanged";
00867 static char vm_reenterpassword[80] = "vm-reenterpassword";
00868 static char vm_mismatch[80] = "vm-mismatch";
00869 static char vm_invalid_password[80] = "vm-invalid-password";
00870 static char vm_pls_try_again[80] = "vm-pls-try-again";
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882 static char vm_prepend_timeout[80] = "vm-then-pound";
00883
00884 static struct ast_flags globalflags = {0};
00885
00886 static int saydurationminfo;
00887
00888 static char dialcontext[AST_MAX_CONTEXT] = "";
00889 static char callcontext[AST_MAX_CONTEXT] = "";
00890 static char exitcontext[AST_MAX_CONTEXT] = "";
00891
00892 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
00893
00894
00895 static char *emailbody = NULL;
00896 static char *emailsubject = NULL;
00897 static char *pagerbody = NULL;
00898 static char *pagersubject = NULL;
00899 static char fromstring[100];
00900 static char pagerfromstring[100];
00901 static char charset[32] = "ISO-8859-1";
00902
00903 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
00904 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
00905 static int adsiver = 1;
00906 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
00907 static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
00908
00909
00910 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00911 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);
00912 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
00913 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
00914 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
00915 signed char record_gain, struct vm_state *vms, char *flag);
00916 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
00917 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
00918 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);
00919 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);
00920 static void apply_options(struct ast_vm_user *vmu, const char *options);
00921 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);
00922 static int is_valid_dtmf(const char *key);
00923 static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
00924 static int write_password_to_file(const char *secretfn, const char *password);
00925 static const char *substitute_escapes(const char *value);
00926 static void free_user(struct ast_vm_user *vmu);
00927
00928 struct ao2_container *inprocess_container;
00929
00930 struct inprocess {
00931 int count;
00932 char *context;
00933 char mailbox[0];
00934 };
00935
00936 static int inprocess_hash_fn(const void *obj, const int flags)
00937 {
00938 const struct inprocess *i = obj;
00939 return atoi(i->mailbox);
00940 }
00941
00942 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
00943 {
00944 struct inprocess *i = obj, *j = arg;
00945 if (strcmp(i->mailbox, j->mailbox)) {
00946 return 0;
00947 }
00948 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
00949 }
00950
00951 static int inprocess_count(const char *context, const char *mailbox, int delta)
00952 {
00953 struct inprocess *i, *arg = ast_alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
00954 arg->context = arg->mailbox + strlen(mailbox) + 1;
00955 strcpy(arg->mailbox, mailbox);
00956 strcpy(arg->context, context);
00957 ao2_lock(inprocess_container);
00958 if ((i = ao2_find(inprocess_container, arg, 0))) {
00959 int ret = ast_atomic_fetchadd_int(&i->count, delta);
00960 ao2_unlock(inprocess_container);
00961 ao2_ref(i, -1);
00962 return ret;
00963 }
00964 if (delta < 0) {
00965 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
00966 }
00967 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
00968 ao2_unlock(inprocess_container);
00969 return 0;
00970 }
00971 i->context = i->mailbox + strlen(mailbox) + 1;
00972 strcpy(i->mailbox, mailbox);
00973 strcpy(i->context, context);
00974 i->count = delta;
00975 ao2_link(inprocess_container, i);
00976 ao2_unlock(inprocess_container);
00977 ao2_ref(i, -1);
00978 return 0;
00979 }
00980
00981 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
00982 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
00983 #endif
00984
00985
00986
00987
00988
00989
00990
00991 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
00992 {
00993 char *bufptr = buf;
00994 for (; *input; input++) {
00995 if (*input < 32) {
00996 continue;
00997 }
00998 *bufptr++ = *input;
00999 if (bufptr == buf + buflen - 1) {
01000 break;
01001 }
01002 }
01003 *bufptr = '\0';
01004 return buf;
01005 }
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021 static void populate_defaults(struct ast_vm_user *vmu)
01022 {
01023 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
01024 vmu->passwordlocation = passwordlocation;
01025 if (saydurationminfo) {
01026 vmu->saydurationm = saydurationminfo;
01027 }
01028 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
01029 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
01030 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
01031 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
01032 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
01033 if (vmminsecs) {
01034 vmu->minsecs = vmminsecs;
01035 }
01036 if (vmmaxsecs) {
01037 vmu->maxsecs = vmmaxsecs;
01038 }
01039 if (maxmsg) {
01040 vmu->maxmsg = maxmsg;
01041 }
01042 if (maxdeletedmsg) {
01043 vmu->maxdeletedmsg = maxdeletedmsg;
01044 }
01045 vmu->volgain = volgain;
01046 ast_free(vmu->emailsubject);
01047 vmu->emailsubject = NULL;
01048 ast_free(vmu->emailbody);
01049 vmu->emailbody = NULL;
01050 #ifdef IMAP_STORAGE
01051 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
01052 #endif
01053 }
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
01064 {
01065 int x;
01066 if (!strcasecmp(var, "attach")) {
01067 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
01068 } else if (!strcasecmp(var, "attachfmt")) {
01069 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
01070 } else if (!strcasecmp(var, "serveremail")) {
01071 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
01072 } else if (!strcasecmp(var, "emailbody")) {
01073 vmu->emailbody = ast_strdup(substitute_escapes(value));
01074 } else if (!strcasecmp(var, "emailsubject")) {
01075 vmu->emailsubject = ast_strdup(substitute_escapes(value));
01076 } else if (!strcasecmp(var, "language")) {
01077 ast_copy_string(vmu->language, value, sizeof(vmu->language));
01078 } else if (!strcasecmp(var, "tz")) {
01079 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
01080 } else if (!strcasecmp(var, "locale")) {
01081 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
01082 #ifdef IMAP_STORAGE
01083 } else if (!strcasecmp(var, "imapuser")) {
01084 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
01085 vmu->imapversion = imapversion;
01086 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
01087 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
01088 vmu->imapversion = imapversion;
01089 } else if (!strcasecmp(var, "imapfolder")) {
01090 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
01091 } else if (!strcasecmp(var, "imapvmshareid")) {
01092 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
01093 vmu->imapversion = imapversion;
01094 #endif
01095 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
01096 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
01097 } else if (!strcasecmp(var, "saycid")){
01098 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
01099 } else if (!strcasecmp(var, "sendvoicemail")){
01100 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
01101 } else if (!strcasecmp(var, "review")){
01102 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
01103 } else if (!strcasecmp(var, "tempgreetwarn")){
01104 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
01105 } else if (!strcasecmp(var, "messagewrap")){
01106 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
01107 } else if (!strcasecmp(var, "operator")) {
01108 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
01109 } else if (!strcasecmp(var, "envelope")){
01110 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
01111 } else if (!strcasecmp(var, "moveheard")){
01112 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
01113 } else if (!strcasecmp(var, "sayduration")){
01114 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
01115 } else if (!strcasecmp(var, "saydurationm")){
01116 if (sscanf(value, "%30d", &x) == 1) {
01117 vmu->saydurationm = x;
01118 } else {
01119 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
01120 }
01121 } else if (!strcasecmp(var, "forcename")){
01122 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
01123 } else if (!strcasecmp(var, "forcegreetings")){
01124 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
01125 } else if (!strcasecmp(var, "callback")) {
01126 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
01127 } else if (!strcasecmp(var, "dialout")) {
01128 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
01129 } else if (!strcasecmp(var, "exitcontext")) {
01130 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
01131 } else if (!strcasecmp(var, "minsecs")) {
01132 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
01133 vmu->minsecs = x;
01134 } else {
01135 ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
01136 vmu->minsecs = vmminsecs;
01137 }
01138 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
01139 vmu->maxsecs = atoi(value);
01140 if (vmu->maxsecs <= 0) {
01141 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
01142 vmu->maxsecs = vmmaxsecs;
01143 } else {
01144 vmu->maxsecs = atoi(value);
01145 }
01146 if (!strcasecmp(var, "maxmessage"))
01147 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
01148 } else if (!strcasecmp(var, "maxmsg")) {
01149 vmu->maxmsg = atoi(value);
01150
01151 if (vmu->maxmsg < 0) {
01152 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
01153 vmu->maxmsg = MAXMSG;
01154 } else if (vmu->maxmsg > MAXMSGLIMIT) {
01155 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
01156 vmu->maxmsg = MAXMSGLIMIT;
01157 }
01158 } else if (!strcasecmp(var, "nextaftercmd")) {
01159 ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
01160 } else if (!strcasecmp(var, "backupdeleted")) {
01161 if (sscanf(value, "%30d", &x) == 1)
01162 vmu->maxdeletedmsg = x;
01163 else if (ast_true(value))
01164 vmu->maxdeletedmsg = MAXMSG;
01165 else
01166 vmu->maxdeletedmsg = 0;
01167
01168 if (vmu->maxdeletedmsg < 0) {
01169 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
01170 vmu->maxdeletedmsg = MAXMSG;
01171 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
01172 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
01173 vmu->maxdeletedmsg = MAXMSGLIMIT;
01174 }
01175 } else if (!strcasecmp(var, "volgain")) {
01176 sscanf(value, "%30lf", &vmu->volgain);
01177 } else if (!strcasecmp(var, "passwordlocation")) {
01178 if (!strcasecmp(value, "spooldir")) {
01179 vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
01180 } else {
01181 vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
01182 }
01183 } else if (!strcasecmp(var, "options")) {
01184 apply_options(vmu, value);
01185 }
01186 }
01187
01188 static char *vm_check_password_shell(char *command, char *buf, size_t len)
01189 {
01190 int fds[2], pid = 0;
01191
01192 memset(buf, 0, len);
01193
01194 if (pipe(fds)) {
01195 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
01196 } else {
01197
01198 pid = ast_safe_fork(0);
01199
01200 if (pid < 0) {
01201
01202 close(fds[0]);
01203 close(fds[1]);
01204 snprintf(buf, len, "FAILURE: Fork failed");
01205 } else if (pid) {
01206
01207 close(fds[1]);
01208 if (read(fds[0], buf, len) < 0) {
01209 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01210 }
01211 close(fds[0]);
01212 } else {
01213
01214 AST_DECLARE_APP_ARGS(arg,
01215 AST_APP_ARG(v)[20];
01216 );
01217 char *mycmd = ast_strdupa(command);
01218
01219 close(fds[0]);
01220 dup2(fds[1], STDOUT_FILENO);
01221 close(fds[1]);
01222 ast_close_fds_above_n(STDOUT_FILENO);
01223
01224 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
01225
01226 execv(arg.v[0], arg.v);
01227 printf("FAILURE: %s", strerror(errno));
01228 _exit(0);
01229 }
01230 }
01231 return buf;
01232 }
01233
01234
01235
01236
01237
01238
01239
01240
01241 static int check_password(struct ast_vm_user *vmu, char *password)
01242 {
01243
01244 if (strlen(password) < minpassword)
01245 return 1;
01246
01247 if (!ast_strlen_zero(password) && password[0] == '*')
01248 return 1;
01249 if (!ast_strlen_zero(ext_pass_check_cmd)) {
01250 char cmd[255], buf[255];
01251
01252 ast_log(AST_LOG_DEBUG, "Verify password policies for %s\n", password);
01253
01254 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01255 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01256 ast_debug(5, "Result: %s\n", buf);
01257 if (!strncasecmp(buf, "VALID", 5)) {
01258 ast_debug(3, "Passed password check: '%s'\n", buf);
01259 return 0;
01260 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01261 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01262 return 0;
01263 } else {
01264 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01265 return 1;
01266 }
01267 }
01268 }
01269 return 0;
01270 }
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01283 {
01284 int res = -1;
01285 if (!strcmp(vmu->password, password)) {
01286
01287 return 0;
01288 }
01289
01290 if (strlen(password) > 10) {
01291 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01292 }
01293 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
01294 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
01295 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01296 res = 0;
01297 }
01298 return res;
01299 }
01300
01301
01302
01303
01304 static void apply_options(struct ast_vm_user *vmu, const char *options)
01305 {
01306 char *stringp;
01307 char *s;
01308 char *var, *value;
01309 stringp = ast_strdupa(options);
01310 while ((s = strsep(&stringp, "|"))) {
01311 value = s;
01312 if ((var = strsep(&value, "=")) && value) {
01313 apply_option(vmu, var, value);
01314 }
01315 }
01316 }
01317
01318
01319
01320
01321
01322
01323 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01324 {
01325 for (; var; var = var->next) {
01326 if (!strcasecmp(var->name, "vmsecret")) {
01327 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01328 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) {
01329 if (ast_strlen_zero(retval->password)) {
01330 if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
01331 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
01332 "\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
01333 } else {
01334 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01335 }
01336 }
01337 } else if (!strcasecmp(var->name, "uniqueid")) {
01338 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
01339 } else if (!strcasecmp(var->name, "pager")) {
01340 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
01341 } else if (!strcasecmp(var->name, "email")) {
01342 ast_copy_string(retval->email, var->value, sizeof(retval->email));
01343 } else if (!strcasecmp(var->name, "fullname")) {
01344 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
01345 } else if (!strcasecmp(var->name, "context")) {
01346 ast_copy_string(retval->context, var->value, sizeof(retval->context));
01347 } else if (!strcasecmp(var->name, "emailsubject")) {
01348 ast_free(retval->emailsubject);
01349 retval->emailsubject = ast_strdup(substitute_escapes(var->value));
01350 } else if (!strcasecmp(var->name, "emailbody")) {
01351 ast_free(retval->emailbody);
01352 retval->emailbody = ast_strdup(substitute_escapes(var->value));
01353 #ifdef IMAP_STORAGE
01354 } else if (!strcasecmp(var->name, "imapuser")) {
01355 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
01356 retval->imapversion = imapversion;
01357 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
01358 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
01359 retval->imapversion = imapversion;
01360 } else if (!strcasecmp(var->name, "imapfolder")) {
01361 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
01362 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01363 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01364 retval->imapversion = imapversion;
01365 #endif
01366 } else
01367 apply_option(retval, var->name, var->value);
01368 }
01369 }
01370
01371
01372
01373
01374
01375
01376
01377
01378 static int is_valid_dtmf(const char *key)
01379 {
01380 int i;
01381 char *local_key = ast_strdupa(key);
01382
01383 for (i = 0; i < strlen(key); ++i) {
01384 if (!strchr(VALID_DTMF, *local_key)) {
01385 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01386 return 0;
01387 }
01388 local_key++;
01389 }
01390 return 1;
01391 }
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01404 {
01405 struct ast_variable *var;
01406 struct ast_vm_user *retval;
01407
01408 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01409 if (ivm) {
01410 memset(retval, 0, sizeof(*retval));
01411 }
01412 populate_defaults(retval);
01413 if (!ivm) {
01414 ast_set_flag(retval, VM_ALLOCED);
01415 }
01416 if (mailbox) {
01417 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01418 }
01419 if (!context && ast_test_flag((&globalflags), VM_SEARCH)) {
01420 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01421 } else {
01422 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01423 }
01424 if (var) {
01425 apply_options_full(retval, var);
01426 ast_variables_destroy(var);
01427 } else {
01428 if (!ivm)
01429 free_user(retval);
01430 retval = NULL;
01431 }
01432 }
01433 return retval;
01434 }
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01445 {
01446
01447 struct ast_vm_user *vmu = NULL, *cur;
01448 AST_LIST_LOCK(&users);
01449
01450 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01451 context = "default";
01452
01453 AST_LIST_TRAVERSE(&users, cur, list) {
01454 #ifdef IMAP_STORAGE
01455 if (cur->imapversion != imapversion) {
01456 continue;
01457 }
01458 #endif
01459 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01460 break;
01461 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01462 break;
01463 }
01464 if (cur) {
01465
01466 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01467 *vmu = *cur;
01468 if (!ivm) {
01469 vmu->emailbody = ast_strdup(cur->emailbody);
01470 vmu->emailsubject = ast_strdup(cur->emailsubject);
01471 }
01472 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01473 AST_LIST_NEXT(vmu, list) = NULL;
01474 }
01475 } else
01476 vmu = find_user_realtime(ivm, context, mailbox);
01477 AST_LIST_UNLOCK(&users);
01478 return vmu;
01479 }
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01492 {
01493
01494 struct ast_vm_user *cur;
01495 int res = -1;
01496 AST_LIST_LOCK(&users);
01497 AST_LIST_TRAVERSE(&users, cur, list) {
01498 if ((!context || !strcasecmp(context, cur->context)) &&
01499 (!strcasecmp(mailbox, cur->mailbox)))
01500 break;
01501 }
01502 if (cur) {
01503 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01504 res = 0;
01505 }
01506 AST_LIST_UNLOCK(&users);
01507 return res;
01508 }
01509
01510
01511
01512
01513
01514
01515
01516
01517 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01518 {
01519 struct ast_config *cfg = NULL;
01520 struct ast_variable *var = NULL;
01521 struct ast_category *cat = NULL;
01522 char *category = NULL, *value = NULL, *new = NULL;
01523 const char *tmp = NULL;
01524 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01525 char secretfn[PATH_MAX] = "";
01526 int found = 0;
01527
01528 if (!change_password_realtime(vmu, newpassword))
01529 return;
01530
01531
01532 switch (vmu->passwordlocation) {
01533 case OPT_PWLOC_SPOOLDIR:
01534 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01535 if (write_password_to_file(secretfn, newpassword) == 0) {
01536 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
01537 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01538 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01539 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01540 break;
01541 } else {
01542 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01543 }
01544
01545 case OPT_PWLOC_VOICEMAILCONF:
01546 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01547 while ((category = ast_category_browse(cfg, category))) {
01548 if (!strcasecmp(category, vmu->context)) {
01549 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01550 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01551 break;
01552 }
01553 value = strstr(tmp, ",");
01554 if (!value) {
01555 new = ast_alloca(strlen(newpassword)+1);
01556 sprintf(new, "%s", newpassword);
01557 } else {
01558 new = ast_alloca((strlen(value) + strlen(newpassword) + 1));
01559 sprintf(new, "%s%s", newpassword, value);
01560 }
01561 if (!(cat = ast_category_get(cfg, category))) {
01562 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01563 break;
01564 }
01565 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01566 found = 1;
01567 }
01568 }
01569
01570 if (found) {
01571 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
01572 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01573 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01574 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01575 break;
01576 }
01577 }
01578
01579 case OPT_PWLOC_USERSCONF:
01580
01581
01582 if ((cfg = ast_config_load("users.conf", config_flags)) && cfg != CONFIG_STATUS_FILEINVALID) {
01583 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01584 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01585 ast_debug(4, "users.conf: %s\n", category);
01586 if (!strcasecmp(category, vmu->mailbox)) {
01587 if (!ast_variable_retrieve(cfg, category, "vmsecret")) {
01588 ast_debug(3, "looks like we need to make vmsecret!\n");
01589 var = ast_variable_new("vmsecret", newpassword, "");
01590 } else {
01591 var = NULL;
01592 }
01593 new = ast_alloca(strlen(newpassword) + 1);
01594 sprintf(new, "%s", newpassword);
01595 if (!(cat = ast_category_get(cfg, category))) {
01596 ast_debug(4, "failed to get category!\n");
01597 ast_free(var);
01598 break;
01599 }
01600 if (!var) {
01601 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01602 } else {
01603 ast_variable_append(cat, var);
01604 }
01605 found = 1;
01606 break;
01607 }
01608 }
01609
01610 if (found) {
01611 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
01612 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01613 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01614 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01615 }
01616 }
01617 }
01618 }
01619
01620 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01621 {
01622 char buf[255];
01623 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01624 ast_debug(1, "External password: %s\n",buf);
01625 if (!ast_safe_system(buf)) {
01626 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
01627 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01628
01629 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01630 }
01631 }
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01647 {
01648 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01649 }
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663 static int make_file(char *dest, const int len, const char *dir, const int num)
01664 {
01665 return snprintf(dest, len, "%s/msg%04d", dir, num);
01666 }
01667
01668
01669 static FILE *vm_mkftemp(char *template)
01670 {
01671 FILE *p = NULL;
01672 int pfd = mkstemp(template);
01673 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01674 if (pfd > -1) {
01675 p = fdopen(pfd, "w+");
01676 if (!p) {
01677 close(pfd);
01678 pfd = -1;
01679 }
01680 }
01681 return p;
01682 }
01683
01684
01685
01686
01687
01688
01689
01690
01691
01692 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01693 {
01694 mode_t mode = VOICEMAIL_DIR_MODE;
01695 int res;
01696
01697 make_dir(dest, len, context, ext, folder);
01698 if ((res = ast_mkdir(dest, mode))) {
01699 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01700 return -1;
01701 }
01702 return 0;
01703 }
01704
01705 static const char * const mailbox_folders[] = {
01706 #ifdef IMAP_STORAGE
01707 imapfolder,
01708 #else
01709 "INBOX",
01710 #endif
01711 "Old",
01712 "Work",
01713 "Family",
01714 "Friends",
01715 "Cust1",
01716 "Cust2",
01717 "Cust3",
01718 "Cust4",
01719 "Cust5",
01720 "Deleted",
01721 "Urgent",
01722 };
01723
01724 static const char *mbox(struct ast_vm_user *vmu, int id)
01725 {
01726 #ifdef IMAP_STORAGE
01727 if (vmu && id == 0) {
01728 return vmu->imapfolder;
01729 }
01730 #endif
01731 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01732 }
01733
01734 static int get_folder_by_name(const char *name)
01735 {
01736 size_t i;
01737
01738 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01739 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01740 return i;
01741 }
01742 }
01743
01744 return -1;
01745 }
01746
01747 static void free_user(struct ast_vm_user *vmu)
01748 {
01749 if (ast_test_flag(vmu, VM_ALLOCED)) {
01750
01751 ast_free(vmu->emailbody);
01752 vmu->emailbody = NULL;
01753
01754 ast_free(vmu->emailsubject);
01755 vmu->emailsubject = NULL;
01756
01757 ast_free(vmu);
01758 }
01759 }
01760
01761 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01762
01763 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01764
01765
01766 if (vms->deleted) {
01767 ast_free(vms->deleted);
01768 vms->deleted = NULL;
01769 }
01770 if (vms->heard) {
01771 ast_free(vms->heard);
01772 vms->heard = NULL;
01773 }
01774 vms->dh_arraysize = 0;
01775
01776 if (arraysize > 0) {
01777 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01778 return -1;
01779 }
01780 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01781 ast_free(vms->deleted);
01782 vms->deleted = NULL;
01783 return -1;
01784 }
01785 vms->dh_arraysize = arraysize;
01786 }
01787
01788 return 0;
01789 }
01790
01791
01792
01793 #ifdef IMAP_STORAGE
01794 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01795 {
01796 char arg[10];
01797 struct vm_state *vms;
01798 unsigned long messageNum;
01799
01800
01801 if (msgnum < 0 && !imapgreetings) {
01802 ast_filedelete(file, NULL);
01803 return;
01804 }
01805
01806 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01807 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);
01808 return;
01809 }
01810
01811 if (msgnum < 0) {
01812 imap_delete_old_greeting(file, vms);
01813 return;
01814 }
01815
01816
01817
01818 messageNum = vms->msgArray[msgnum];
01819 if (messageNum == 0) {
01820 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01821 return;
01822 }
01823 if (option_debug > 2)
01824 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01825
01826 snprintf (arg, sizeof(arg), "%lu", messageNum);
01827 ast_mutex_lock(&vms->lock);
01828 mail_setflag (vms->mailstream, arg, "\\DELETED");
01829 mail_expunge(vms->mailstream);
01830 ast_mutex_unlock(&vms->lock);
01831 }
01832
01833 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01834 {
01835 struct vm_state *vms_p;
01836 char *file, *filename;
01837 char *attachment;
01838 int i;
01839 BODY *body;
01840
01841
01842
01843
01844 if (msgnum > -1 || !imapgreetings) {
01845 return 0;
01846 } else {
01847 file = strrchr(ast_strdupa(dir), '/');
01848 if (file)
01849 *file++ = '\0';
01850 else {
01851 ast_debug (1, "Failed to procure file name from directory passed.\n");
01852 return -1;
01853 }
01854 }
01855
01856
01857 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01858 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01859
01860
01861
01862
01863 if (!(vms_p = create_vm_state_from_user(vmu))) {
01864 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01865 return -1;
01866 }
01867 }
01868
01869
01870 *vms_p->introfn = '\0';
01871
01872 ast_mutex_lock(&vms_p->lock);
01873 init_mailstream(vms_p, GREETINGS_FOLDER);
01874 if (!vms_p->mailstream) {
01875 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01876 ast_mutex_unlock(&vms_p->lock);
01877 return -1;
01878 }
01879
01880
01881 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01882 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01883
01884 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01885 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01886 } else {
01887 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01888 ast_mutex_unlock(&vms_p->lock);
01889 return -1;
01890 }
01891 filename = strsep(&attachment, ".");
01892 if (!strcmp(filename, file)) {
01893 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01894 vms_p->msgArray[vms_p->curmsg] = i + 1;
01895 save_body(body, vms_p, "2", attachment, 0);
01896 ast_mutex_unlock(&vms_p->lock);
01897 return 0;
01898 }
01899 }
01900 ast_mutex_unlock(&vms_p->lock);
01901
01902 return -1;
01903 }
01904
01905 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01906 {
01907 BODY *body;
01908 char *header_content;
01909 char *attachedfilefmt;
01910 char buf[80];
01911 struct vm_state *vms;
01912 char text_file[PATH_MAX];
01913 FILE *text_file_ptr;
01914 int res = 0;
01915 struct ast_vm_user *vmu;
01916
01917 if (!(vmu = find_user(NULL, context, mailbox))) {
01918 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01919 return -1;
01920 }
01921
01922 if (msgnum < 0) {
01923 if (imapgreetings) {
01924 res = imap_retrieve_greeting(dir, msgnum, vmu);
01925 goto exit;
01926 } else {
01927 res = 0;
01928 goto exit;
01929 }
01930 }
01931
01932
01933
01934
01935 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01936
01937
01938
01939
01940
01941
01942
01943 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01944 res = -1;
01945 goto exit;
01946 }
01947
01948 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01949 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01950
01951
01952 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01953 res = 0;
01954 goto exit;
01955 }
01956
01957 if (option_debug > 2)
01958 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01959 if (vms->msgArray[msgnum] == 0) {
01960 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01961 res = -1;
01962 goto exit;
01963 }
01964
01965
01966 ast_mutex_lock(&vms->lock);
01967 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01968 ast_mutex_unlock(&vms->lock);
01969
01970 if (ast_strlen_zero(header_content)) {
01971 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01972 res = -1;
01973 goto exit;
01974 }
01975
01976 ast_mutex_lock(&vms->lock);
01977 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01978 ast_mutex_unlock(&vms->lock);
01979
01980
01981 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01982 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01983 } else {
01984 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01985 res = -1;
01986 goto exit;
01987 }
01988
01989
01990
01991 strsep(&attachedfilefmt, ".");
01992 if (!attachedfilefmt) {
01993 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
01994 res = -1;
01995 goto exit;
01996 }
01997
01998 save_body(body, vms, "2", attachedfilefmt, 0);
01999 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
02000 *vms->introfn = '\0';
02001 }
02002
02003
02004 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
02005
02006 if (!(text_file_ptr = fopen(text_file, "w"))) {
02007 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
02008 }
02009
02010 fprintf(text_file_ptr, "%s\n", "[message]");
02011
02012 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
02013 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
02014 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
02015 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
02016 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
02017 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
02018 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
02019 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
02020 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
02021 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
02022 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
02023 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
02024 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
02025 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
02026 fclose(text_file_ptr);
02027
02028 exit:
02029 free_user(vmu);
02030 return res;
02031 }
02032
02033 static int folder_int(const char *folder)
02034 {
02035
02036 if (!folder) {
02037 return 0;
02038 }
02039 if (!strcasecmp(folder, imapfolder)) {
02040 return 0;
02041 } else if (!strcasecmp(folder, "Old")) {
02042 return 1;
02043 } else if (!strcasecmp(folder, "Work")) {
02044 return 2;
02045 } else if (!strcasecmp(folder, "Family")) {
02046 return 3;
02047 } else if (!strcasecmp(folder, "Friends")) {
02048 return 4;
02049 } else if (!strcasecmp(folder, "Cust1")) {
02050 return 5;
02051 } else if (!strcasecmp(folder, "Cust2")) {
02052 return 6;
02053 } else if (!strcasecmp(folder, "Cust3")) {
02054 return 7;
02055 } else if (!strcasecmp(folder, "Cust4")) {
02056 return 8;
02057 } else if (!strcasecmp(folder, "Cust5")) {
02058 return 9;
02059 } else if (!strcasecmp(folder, "Urgent")) {
02060 return 11;
02061 } else {
02062 return 0;
02063 }
02064 }
02065
02066 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02067 {
02068 SEARCHPGM *pgm;
02069 SEARCHHEADER *hdr;
02070
02071 struct ast_vm_user *vmu, vmus;
02072 struct vm_state *vms_p;
02073 int ret = 0;
02074 int fold = folder_int(folder);
02075 int urgent = 0;
02076
02077
02078 if (fold == 11) {
02079 fold = NEW_FOLDER;
02080 urgent = 1;
02081 }
02082
02083 if (ast_strlen_zero(mailbox))
02084 return 0;
02085
02086
02087 vmu = find_user(&vmus, context, mailbox);
02088 if (!vmu) {
02089 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02090 return -1;
02091 } else {
02092
02093 if (vmu->imapuser[0] == '\0') {
02094 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02095 return -1;
02096 }
02097 }
02098
02099
02100 if (vmu->imapuser[0] == '\0') {
02101 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02102 free_user(vmu);
02103 return -1;
02104 }
02105
02106
02107 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02108 if (!vms_p) {
02109 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02110 }
02111 if (vms_p) {
02112 ast_debug(3, "Returning before search - user is logged in\n");
02113 if (fold == 0) {
02114 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02115 }
02116 if (fold == 1) {
02117 return vms_p->oldmessages;
02118 }
02119 }
02120
02121
02122 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02123 if (!vms_p) {
02124 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02125 }
02126
02127 if (!vms_p) {
02128 vms_p = create_vm_state_from_user(vmu);
02129 }
02130 ret = init_mailstream(vms_p, fold);
02131 if (!vms_p->mailstream) {
02132 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02133 return -1;
02134 }
02135 if (ret == 0) {
02136 ast_mutex_lock(&vms_p->lock);
02137 pgm = mail_newsearchpgm ();
02138 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02139 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02140 pgm->header = hdr;
02141 if (fold != OLD_FOLDER) {
02142 pgm->unseen = 1;
02143 pgm->seen = 0;
02144 }
02145
02146
02147
02148 else {
02149 pgm->unseen = 0;
02150 pgm->seen = 1;
02151 }
02152
02153 if (fold == NEW_FOLDER) {
02154 if (urgent) {
02155 pgm->flagged = 1;
02156 pgm->unflagged = 0;
02157 } else {
02158 pgm->flagged = 0;
02159 pgm->unflagged = 1;
02160 }
02161 }
02162 pgm->undeleted = 1;
02163 pgm->deleted = 0;
02164
02165 vms_p->vmArrayIndex = 0;
02166 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02167 if (fold == 0 && urgent == 0)
02168 vms_p->newmessages = vms_p->vmArrayIndex;
02169 if (fold == 1)
02170 vms_p->oldmessages = vms_p->vmArrayIndex;
02171 if (fold == 0 && urgent == 1)
02172 vms_p->urgentmessages = vms_p->vmArrayIndex;
02173
02174 mail_free_searchpgm(&pgm);
02175 ast_mutex_unlock(&vms_p->lock);
02176 vms_p->updated = 0;
02177 return vms_p->vmArrayIndex;
02178 } else {
02179 ast_mutex_lock(&vms_p->lock);
02180 mail_ping(vms_p->mailstream);
02181 ast_mutex_unlock(&vms_p->lock);
02182 }
02183 return 0;
02184 }
02185
02186 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02187 {
02188
02189 check_quota(vms, vmu->imapfolder);
02190 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02191 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02192 ast_play_and_wait(chan, "vm-mailboxfull");
02193 return -1;
02194 }
02195
02196
02197 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));
02198 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02199 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02200 ast_play_and_wait(chan, "vm-mailboxfull");
02201 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02202 return -1;
02203 }
02204
02205 return 0;
02206 }
02207
02208
02209
02210
02211
02212
02213
02214
02215
02216
02217 static int messagecount(const char *context, const char *mailbox, const char *folder)
02218 {
02219 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02220 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02221 } else {
02222 return __messagecount(context, mailbox, folder);
02223 }
02224 }
02225
02226 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)
02227 {
02228 char *myserveremail = serveremail;
02229 char fn[PATH_MAX];
02230 char introfn[PATH_MAX];
02231 char mailbox[256];
02232 char *stringp;
02233 FILE *p = NULL;
02234 char tmp[80] = "/tmp/astmail-XXXXXX";
02235 long len;
02236 void *buf;
02237 int tempcopy = 0;
02238 STRING str;
02239 int ret;
02240 char *imap_flags = NIL;
02241 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02242 int box = NEW_FOLDER;
02243
02244
02245 if (msgnum < 0) {
02246 if(!imapgreetings) {
02247 return 0;
02248 } else {
02249 box = GREETINGS_FOLDER;
02250 }
02251 }
02252
02253 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02254 return -1;
02255 }
02256
02257
02258 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02259 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02260 imap_flags = "\\FLAGGED";
02261 }
02262
02263
02264 fmt = ast_strdupa(fmt);
02265 stringp = fmt;
02266 strsep(&stringp, "|");
02267
02268 if (!ast_strlen_zero(vmu->serveremail))
02269 myserveremail = vmu->serveremail;
02270
02271 if (msgnum > -1)
02272 make_file(fn, sizeof(fn), dir, msgnum);
02273 else
02274 ast_copy_string (fn, dir, sizeof(fn));
02275
02276 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02277 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02278 *introfn = '\0';
02279 }
02280
02281 if (ast_strlen_zero(vmu->email)) {
02282
02283
02284
02285
02286
02287 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02288 tempcopy = 1;
02289 }
02290
02291 if (!strcmp(fmt, "wav49"))
02292 fmt = "WAV";
02293 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02294
02295
02296
02297 if (!(p = vm_mkftemp(tmp))) {
02298 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02299 if (tempcopy)
02300 *(vmu->email) = '\0';
02301 return -1;
02302 }
02303
02304 if (msgnum < 0 && imapgreetings) {
02305 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02306 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02307 return -1;
02308 }
02309 imap_delete_old_greeting(fn, vms);
02310 }
02311
02312 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02313 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02314 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02315 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02316
02317 len = ftell(p);
02318 rewind(p);
02319 if (!(buf = ast_malloc(len + 1))) {
02320 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02321 fclose(p);
02322 if (tempcopy)
02323 *(vmu->email) = '\0';
02324 return -1;
02325 }
02326 if (fread(buf, len, 1, p) < len) {
02327 if (ferror(p)) {
02328 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02329 return -1;
02330 }
02331 }
02332 ((char *) buf)[len] = '\0';
02333 INIT(&str, mail_string, buf, len);
02334 ret = init_mailstream(vms, box);
02335 if (ret == 0) {
02336 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
02337 ast_mutex_lock(&vms->lock);
02338 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02339 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02340 ast_mutex_unlock(&vms->lock);
02341 fclose(p);
02342 unlink(tmp);
02343 ast_free(buf);
02344 } else {
02345 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02346 fclose(p);
02347 unlink(tmp);
02348 ast_free(buf);
02349 return -1;
02350 }
02351 ast_debug(3, "%s stored\n", fn);
02352
02353 if (tempcopy)
02354 *(vmu->email) = '\0';
02355 inprocess_count(vmu->mailbox, vmu->context, -1);
02356 return 0;
02357
02358 }
02359
02360
02361
02362
02363
02364
02365
02366
02367
02368
02369
02370
02371
02372
02373 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02374 {
02375 char tmp[PATH_MAX] = "";
02376 char *mailboxnc;
02377 char *context;
02378 char *mb;
02379 char *cur;
02380 if (newmsgs)
02381 *newmsgs = 0;
02382 if (oldmsgs)
02383 *oldmsgs = 0;
02384 if (urgentmsgs)
02385 *urgentmsgs = 0;
02386
02387 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02388
02389 if (ast_strlen_zero(mailbox_context))
02390 return 0;
02391
02392 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02393 context = strchr(tmp, '@');
02394 if (strchr(mailbox_context, ',')) {
02395 int tmpnew, tmpold, tmpurgent;
02396 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02397 mb = tmp;
02398 while ((cur = strsep(&mb, ", "))) {
02399 if (!ast_strlen_zero(cur)) {
02400 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02401 return -1;
02402 else {
02403 if (newmsgs)
02404 *newmsgs += tmpnew;
02405 if (oldmsgs)
02406 *oldmsgs += tmpold;
02407 if (urgentmsgs)
02408 *urgentmsgs += tmpurgent;
02409 }
02410 }
02411 }
02412 return 0;
02413 }
02414 if (context) {
02415 *context = '\0';
02416 mailboxnc = tmp;
02417 context++;
02418 } else {
02419 context = "default";
02420 mailboxnc = (char *) mailbox_context;
02421 }
02422
02423 if (newmsgs) {
02424 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02425 if (!vmu) {
02426 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02427 return -1;
02428 }
02429 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02430 free_user(vmu);
02431 return -1;
02432 }
02433 free_user(vmu);
02434 }
02435 if (oldmsgs) {
02436 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02437 return -1;
02438 }
02439 }
02440 if (urgentmsgs) {
02441 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02442 return -1;
02443 }
02444 }
02445 return 0;
02446 }
02447
02448
02449
02450
02451
02452
02453
02454
02455
02456
02457
02458 static int has_voicemail(const char *mailbox, const char *folder)
02459 {
02460 char tmp[256], *tmp2, *box, *context;
02461 ast_copy_string(tmp, mailbox, sizeof(tmp));
02462 tmp2 = tmp;
02463 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02464 while ((box = strsep(&tmp2, ",&"))) {
02465 if (!ast_strlen_zero(box)) {
02466 if (has_voicemail(box, folder)) {
02467 return 1;
02468 }
02469 }
02470 }
02471 }
02472 if ((context = strchr(tmp, '@'))) {
02473 *context++ = '\0';
02474 } else {
02475 context = "default";
02476 }
02477 return __messagecount(context, tmp, folder) ? 1 : 0;
02478 }
02479
02480
02481
02482
02483
02484
02485
02486
02487
02488
02489
02490
02491
02492
02493
02494
02495 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)
02496 {
02497 struct vm_state *sendvms = NULL, *destvms = NULL;
02498 char messagestring[10];
02499 if (msgnum >= recip->maxmsg) {
02500 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02501 return -1;
02502 }
02503 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02504 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02505 return -1;
02506 }
02507 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02508 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02509 return -1;
02510 }
02511 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02512 ast_mutex_lock(&sendvms->lock);
02513 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02514 ast_mutex_unlock(&sendvms->lock);
02515 return 0;
02516 }
02517 ast_mutex_unlock(&sendvms->lock);
02518 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02519 return -1;
02520 }
02521
02522 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02523 {
02524 char tmp[256], *t = tmp;
02525 size_t left = sizeof(tmp);
02526
02527 if (box == OLD_FOLDER) {
02528 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02529 } else {
02530 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02531 }
02532
02533 if (box == NEW_FOLDER) {
02534 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02535 } else {
02536 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02537 }
02538
02539
02540 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02541
02542
02543 if (!ast_strlen_zero(authuser))
02544 ast_build_string(&t, &left, "/authuser=%s", authuser);
02545
02546
02547 if (!ast_strlen_zero(imapflags))
02548 ast_build_string(&t, &left, "/%s", imapflags);
02549
02550
02551 #if 1
02552 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02553 #else
02554 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02555 #endif
02556 if (box == NEW_FOLDER || box == OLD_FOLDER)
02557 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02558 else if (box == GREETINGS_FOLDER)
02559 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02560 else {
02561 if (!ast_strlen_zero(imapparentfolder)) {
02562
02563 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02564 } else {
02565 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02566 }
02567 }
02568 }
02569
02570 static int init_mailstream(struct vm_state *vms, int box)
02571 {
02572 MAILSTREAM *stream = NIL;
02573 long debug;
02574 char tmp[256];
02575
02576 if (!vms) {
02577 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02578 return -1;
02579 }
02580 if (option_debug > 2)
02581 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02582 if (vms->mailstream == NIL || !vms->mailstream) {
02583 if (option_debug)
02584 ast_log(LOG_DEBUG, "mailstream not set.\n");
02585 } else {
02586 stream = vms->mailstream;
02587 }
02588
02589 debug = NIL;
02590
02591 if (delimiter == '\0') {
02592 char *cp;
02593 #ifdef USE_SYSTEM_IMAP
02594 #include <imap/linkage.c>
02595 #elif defined(USE_SYSTEM_CCLIENT)
02596 #include <c-client/linkage.c>
02597 #else
02598 #include "linkage.c"
02599 #endif
02600
02601 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02602 ast_mutex_lock(&vms->lock);
02603 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02604 ast_mutex_unlock(&vms->lock);
02605 if (stream == NIL) {
02606 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02607 return -1;
02608 }
02609 get_mailbox_delimiter(stream);
02610
02611 for (cp = vms->imapfolder; *cp; cp++)
02612 if (*cp == '/')
02613 *cp = delimiter;
02614 }
02615
02616 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02617 if (option_debug > 2)
02618 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02619 ast_mutex_lock(&vms->lock);
02620 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02621 ast_mutex_unlock(&vms->lock);
02622 if (vms->mailstream == NIL) {
02623 return -1;
02624 } else {
02625 return 0;
02626 }
02627 }
02628
02629 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02630 {
02631 SEARCHPGM *pgm;
02632 SEARCHHEADER *hdr;
02633 int ret, urgent = 0;
02634
02635
02636 if (box == 11) {
02637 box = NEW_FOLDER;
02638 urgent = 1;
02639 }
02640
02641 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02642 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02643 vms->imapversion = vmu->imapversion;
02644 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02645
02646 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02647 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02648 return -1;
02649 }
02650
02651 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02652
02653
02654 if (box == 0) {
02655 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02656 check_quota(vms, (char *) mbox(vmu, box));
02657 }
02658
02659 ast_mutex_lock(&vms->lock);
02660 pgm = mail_newsearchpgm();
02661
02662
02663 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02664 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02665 pgm->header = hdr;
02666 pgm->deleted = 0;
02667 pgm->undeleted = 1;
02668
02669
02670 if (box == NEW_FOLDER && urgent == 1) {
02671 pgm->unseen = 1;
02672 pgm->seen = 0;
02673 pgm->flagged = 1;
02674 pgm->unflagged = 0;
02675 } else if (box == NEW_FOLDER && urgent == 0) {
02676 pgm->unseen = 1;
02677 pgm->seen = 0;
02678 pgm->flagged = 0;
02679 pgm->unflagged = 1;
02680 } else if (box == OLD_FOLDER) {
02681 pgm->seen = 1;
02682 pgm->unseen = 0;
02683 }
02684
02685 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02686
02687 vms->vmArrayIndex = 0;
02688 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02689 vms->lastmsg = vms->vmArrayIndex - 1;
02690 mail_free_searchpgm(&pgm);
02691
02692
02693
02694
02695 if (box == 0 && !vms->dh_arraysize) {
02696 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02697 }
02698 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02699 ast_mutex_unlock(&vms->lock);
02700 return -1;
02701 }
02702
02703 ast_mutex_unlock(&vms->lock);
02704 return 0;
02705 }
02706
02707 static void write_file(char *filename, char *buffer, unsigned long len)
02708 {
02709 FILE *output;
02710
02711 output = fopen (filename, "w");
02712 if (fwrite(buffer, len, 1, output) != 1) {
02713 if (ferror(output)) {
02714 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02715 }
02716 }
02717 fclose (output);
02718 }
02719
02720 static void update_messages_by_imapuser(const char *user, unsigned long number)
02721 {
02722 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02723
02724 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02725 return;
02726 }
02727
02728 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02729 vms->msgArray[vms->vmArrayIndex++] = number;
02730 }
02731
02732 void mm_searched(MAILSTREAM *stream, unsigned long number)
02733 {
02734 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02735
02736 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02737 return;
02738
02739 update_messages_by_imapuser(user, number);
02740 }
02741
02742 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02743 {
02744 struct ast_variable *var;
02745 struct ast_vm_user *vmu;
02746
02747 vmu = ast_calloc(1, sizeof *vmu);
02748 if (!vmu)
02749 return NULL;
02750
02751 populate_defaults(vmu);
02752 ast_set_flag(vmu, VM_ALLOCED);
02753
02754 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02755 if (var) {
02756 apply_options_full(vmu, var);
02757 ast_variables_destroy(var);
02758 return vmu;
02759 } else {
02760 ast_free(vmu);
02761 return NULL;
02762 }
02763 }
02764
02765
02766
02767 void mm_exists(MAILSTREAM * stream, unsigned long number)
02768 {
02769
02770 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02771 if (number == 0) return;
02772 set_update(stream);
02773 }
02774
02775
02776 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02777 {
02778
02779 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02780 if (number == 0) return;
02781 set_update(stream);
02782 }
02783
02784
02785 void mm_flags(MAILSTREAM * stream, unsigned long number)
02786 {
02787
02788 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02789 if (number == 0) return;
02790 set_update(stream);
02791 }
02792
02793
02794 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02795 {
02796 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02797 mm_log (string, errflg);
02798 }
02799
02800
02801 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02802 {
02803 if (delimiter == '\0') {
02804 delimiter = delim;
02805 }
02806
02807 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02808 if (attributes & LATT_NOINFERIORS)
02809 ast_debug(5, "no inferiors\n");
02810 if (attributes & LATT_NOSELECT)
02811 ast_debug(5, "no select\n");
02812 if (attributes & LATT_MARKED)
02813 ast_debug(5, "marked\n");
02814 if (attributes & LATT_UNMARKED)
02815 ast_debug(5, "unmarked\n");
02816 }
02817
02818
02819 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02820 {
02821 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02822 if (attributes & LATT_NOINFERIORS)
02823 ast_debug(5, "no inferiors\n");
02824 if (attributes & LATT_NOSELECT)
02825 ast_debug(5, "no select\n");
02826 if (attributes & LATT_MARKED)
02827 ast_debug(5, "marked\n");
02828 if (attributes & LATT_UNMARKED)
02829 ast_debug(5, "unmarked\n");
02830 }
02831
02832
02833 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02834 {
02835 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02836 if (status->flags & SA_MESSAGES)
02837 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02838 if (status->flags & SA_RECENT)
02839 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02840 if (status->flags & SA_UNSEEN)
02841 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02842 if (status->flags & SA_UIDVALIDITY)
02843 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02844 if (status->flags & SA_UIDNEXT)
02845 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02846 ast_log(AST_LOG_NOTICE, "\n");
02847 }
02848
02849
02850 void mm_log(char *string, long errflg)
02851 {
02852 switch ((short) errflg) {
02853 case NIL:
02854 ast_debug(1, "IMAP Info: %s\n", string);
02855 break;
02856 case PARSE:
02857 case WARN:
02858 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02859 break;
02860 case ERROR:
02861 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02862 break;
02863 }
02864 }
02865
02866
02867 void mm_dlog(char *string)
02868 {
02869 ast_log(AST_LOG_NOTICE, "%s\n", string);
02870 }
02871
02872
02873 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02874 {
02875 struct ast_vm_user *vmu;
02876
02877 ast_debug(4, "Entering callback mm_login\n");
02878
02879 ast_copy_string(user, mb->user, MAILTMPLEN);
02880
02881
02882 if (!ast_strlen_zero(authpassword)) {
02883 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02884 } else {
02885 AST_LIST_TRAVERSE(&users, vmu, list) {
02886 if (!strcasecmp(mb->user, vmu->imapuser)) {
02887 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02888 break;
02889 }
02890 }
02891 if (!vmu) {
02892 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02893 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02894 free_user(vmu);
02895 }
02896 }
02897 }
02898 }
02899
02900
02901 void mm_critical(MAILSTREAM * stream)
02902 {
02903 }
02904
02905
02906 void mm_nocritical(MAILSTREAM * stream)
02907 {
02908 }
02909
02910
02911 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02912 {
02913 kill (getpid (), SIGSTOP);
02914 return NIL;
02915 }
02916
02917
02918 void mm_fatal(char *string)
02919 {
02920 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02921 }
02922
02923
02924 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02925 {
02926 struct vm_state *vms;
02927 char *mailbox = stream->mailbox, *user;
02928 char buf[1024] = "";
02929 unsigned long usage = 0, limit = 0;
02930
02931 while (pquota) {
02932 usage = pquota->usage;
02933 limit = pquota->limit;
02934 pquota = pquota->next;
02935 }
02936
02937 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)))) {
02938 ast_log(AST_LOG_ERROR, "No state found.\n");
02939 return;
02940 }
02941
02942 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02943
02944 vms->quota_usage = usage;
02945 vms->quota_limit = limit;
02946 }
02947
02948 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02949 {
02950 char *start, *eol_pnt;
02951 int taglen;
02952
02953 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02954 return NULL;
02955
02956 taglen = strlen(tag) + 1;
02957 if (taglen < 1)
02958 return NULL;
02959
02960 if (!(start = strstr(header, tag)))
02961 return NULL;
02962
02963
02964 memset(buf, 0, len);
02965
02966 ast_copy_string(buf, start+taglen, len);
02967 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02968 *eol_pnt = '\0';
02969 return buf;
02970 }
02971
02972 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02973 {
02974 char *start, *quote, *eol_pnt;
02975
02976 if (ast_strlen_zero(mailbox))
02977 return NULL;
02978
02979 if (!(start = strstr(mailbox, "/user=")))
02980 return NULL;
02981
02982 ast_copy_string(buf, start+6, len);
02983
02984 if (!(quote = strchr(buf, '\"'))) {
02985 if (!(eol_pnt = strchr(buf, '/')))
02986 eol_pnt = strchr(buf,'}');
02987 *eol_pnt = '\0';
02988 return buf;
02989 } else {
02990 eol_pnt = strchr(buf+1,'\"');
02991 *eol_pnt = '\0';
02992 return buf+1;
02993 }
02994 }
02995
02996 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
02997 {
02998 struct vm_state *vms_p;
02999
03000 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03001 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
03002 return vms_p;
03003 }
03004 if (option_debug > 4)
03005 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
03006 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
03007 return NULL;
03008 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
03009 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
03010 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
03011 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
03012 vms_p->mailstream = NIL;
03013 vms_p->imapversion = vmu->imapversion;
03014 if (option_debug > 4)
03015 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
03016 vms_p->updated = 1;
03017
03018 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
03019 init_vm_state(vms_p);
03020 vmstate_insert(vms_p);
03021 return vms_p;
03022 }
03023
03024 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
03025 {
03026 struct vmstate *vlist = NULL;
03027
03028 if (interactive) {
03029 struct vm_state *vms;
03030 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03031 vms = pthread_getspecific(ts_vmstate.key);
03032 return vms;
03033 }
03034
03035 AST_LIST_LOCK(&vmstates);
03036 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03037 if (!vlist->vms) {
03038 ast_debug(3, "error: vms is NULL for %s\n", user);
03039 continue;
03040 }
03041 if (vlist->vms->imapversion != imapversion) {
03042 continue;
03043 }
03044 if (!vlist->vms->imapuser) {
03045 ast_debug(3, "error: imapuser is NULL for %s\n", user);
03046 continue;
03047 }
03048
03049 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
03050 AST_LIST_UNLOCK(&vmstates);
03051 return vlist->vms;
03052 }
03053 }
03054 AST_LIST_UNLOCK(&vmstates);
03055
03056 ast_debug(3, "%s not found in vmstates\n", user);
03057
03058 return NULL;
03059 }
03060
03061 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
03062 {
03063
03064 struct vmstate *vlist = NULL;
03065 const char *local_context = S_OR(context, "default");
03066
03067 if (interactive) {
03068 struct vm_state *vms;
03069 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03070 vms = pthread_getspecific(ts_vmstate.key);
03071 return vms;
03072 }
03073
03074 AST_LIST_LOCK(&vmstates);
03075 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03076 if (!vlist->vms) {
03077 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03078 continue;
03079 }
03080 if (vlist->vms->imapversion != imapversion) {
03081 continue;
03082 }
03083 if (!vlist->vms->username || !vlist->vms->context) {
03084 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03085 continue;
03086 }
03087
03088 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);
03089
03090 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03091 ast_debug(3, "Found it!\n");
03092 AST_LIST_UNLOCK(&vmstates);
03093 return vlist->vms;
03094 }
03095 }
03096 AST_LIST_UNLOCK(&vmstates);
03097
03098 ast_debug(3, "%s not found in vmstates\n", mailbox);
03099
03100 return NULL;
03101 }
03102
03103 static void vmstate_insert(struct vm_state *vms)
03104 {
03105 struct vmstate *v;
03106 struct vm_state *altvms;
03107
03108
03109
03110
03111 if (vms->interactive == 1) {
03112 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03113 if (altvms) {
03114 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03115 vms->newmessages = altvms->newmessages;
03116 vms->oldmessages = altvms->oldmessages;
03117 vms->vmArrayIndex = altvms->vmArrayIndex;
03118 vms->lastmsg = altvms->lastmsg;
03119 vms->curmsg = altvms->curmsg;
03120
03121 vms->persist_vms = altvms;
03122
03123 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03124 vms->mailstream = altvms->mailstream;
03125 #else
03126 vms->mailstream = NIL;
03127 #endif
03128 }
03129 return;
03130 }
03131
03132 if (!(v = ast_calloc(1, sizeof(*v))))
03133 return;
03134
03135 v->vms = vms;
03136
03137 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03138
03139 AST_LIST_LOCK(&vmstates);
03140 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03141 AST_LIST_UNLOCK(&vmstates);
03142 }
03143
03144 static void vmstate_delete(struct vm_state *vms)
03145 {
03146 struct vmstate *vc = NULL;
03147 struct vm_state *altvms = NULL;
03148
03149
03150
03151 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03152 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03153 altvms->newmessages = vms->newmessages;
03154 altvms->oldmessages = vms->oldmessages;
03155 altvms->updated = 1;
03156 vms->mailstream = mail_close(vms->mailstream);
03157
03158
03159 return;
03160 }
03161
03162 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03163
03164 AST_LIST_LOCK(&vmstates);
03165 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03166 if (vc->vms == vms) {
03167 AST_LIST_REMOVE_CURRENT(list);
03168 break;
03169 }
03170 }
03171 AST_LIST_TRAVERSE_SAFE_END
03172 AST_LIST_UNLOCK(&vmstates);
03173
03174 if (vc) {
03175 ast_mutex_destroy(&vc->vms->lock);
03176 ast_free(vc);
03177 }
03178 else
03179 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03180 }
03181
03182 static void set_update(MAILSTREAM * stream)
03183 {
03184 struct vm_state *vms;
03185 char *mailbox = stream->mailbox, *user;
03186 char buf[1024] = "";
03187
03188 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03189 if (user && option_debug > 2)
03190 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03191 return;
03192 }
03193
03194 ast_debug(3, "User %s mailbox set for update.\n", user);
03195
03196 vms->updated = 1;
03197 }
03198
03199 static void init_vm_state(struct vm_state *vms)
03200 {
03201 int x;
03202 vms->vmArrayIndex = 0;
03203 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
03204 vms->msgArray[x] = 0;
03205 }
03206 ast_mutex_init(&vms->lock);
03207 }
03208
03209 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03210 {
03211 char *body_content;
03212 char *body_decoded;
03213 char *fn = is_intro ? vms->introfn : vms->fn;
03214 unsigned long len;
03215 unsigned long newlen;
03216 char filename[256];
03217
03218 if (!body || body == NIL)
03219 return -1;
03220
03221 ast_mutex_lock(&vms->lock);
03222 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03223 ast_mutex_unlock(&vms->lock);
03224 if (body_content != NIL) {
03225 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03226
03227 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03228
03229 if (!newlen) {
03230 return -1;
03231 }
03232 write_file(filename, (char *) body_decoded, newlen);
03233 } else {
03234 ast_debug(5, "Body of message is NULL.\n");
03235 return -1;
03236 }
03237 return 0;
03238 }
03239
03240
03241
03242
03243
03244
03245
03246
03247 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03248 char tmp[50];
03249 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03250 mail_list(stream, tmp, "*");
03251 }
03252
03253
03254
03255
03256
03257
03258
03259
03260 static void check_quota(struct vm_state *vms, char *mailbox) {
03261 ast_mutex_lock(&vms->lock);
03262 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03263 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03264 if (vms && vms->mailstream != NULL) {
03265 imap_getquotaroot(vms->mailstream, mailbox);
03266 } else {
03267 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03268 }
03269 ast_mutex_unlock(&vms->lock);
03270 }
03271
03272 #endif
03273
03274
03275
03276
03277
03278 static int vm_lock_path(const char *path)
03279 {
03280 switch (ast_lock_path(path)) {
03281 case AST_LOCK_TIMEOUT:
03282 return -1;
03283 default:
03284 return 0;
03285 }
03286 }
03287
03288
03289 #ifdef ODBC_STORAGE
03290 struct generic_prepare_struct {
03291 char *sql;
03292 int argc;
03293 char **argv;
03294 };
03295
03296 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03297 {
03298 struct generic_prepare_struct *gps = data;
03299 int res, i;
03300 SQLHSTMT stmt;
03301
03302 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03303 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03304 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03305 return NULL;
03306 }
03307 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03308 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03309 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03310 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03311 return NULL;
03312 }
03313 for (i = 0; i < gps->argc; i++)
03314 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03315
03316 return stmt;
03317 }
03318
03319
03320
03321
03322
03323
03324
03325
03326
03327
03328
03329
03330
03331
03332
03333 static int retrieve_file(char *dir, int msgnum)
03334 {
03335 int x = 0;
03336 int res;
03337 int fd = -1;
03338 size_t fdlen = 0;
03339 void *fdm = MAP_FAILED;
03340 SQLSMALLINT colcount = 0;
03341 SQLHSTMT stmt;
03342 char sql[PATH_MAX];
03343 char fmt[80]="";
03344 char *c;
03345 char coltitle[256];
03346 SQLSMALLINT collen;
03347 SQLSMALLINT datatype;
03348 SQLSMALLINT decimaldigits;
03349 SQLSMALLINT nullable;
03350 SQLULEN colsize;
03351 SQLLEN colsize2;
03352 FILE *f = NULL;
03353 char rowdata[80];
03354 char fn[PATH_MAX];
03355 char full_fn[PATH_MAX];
03356 char msgnums[80];
03357 char *argv[] = { dir, msgnums };
03358 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03359
03360 struct odbc_obj *obj;
03361 obj = ast_odbc_request_obj(odbc_database, 0);
03362 if (obj) {
03363 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03364 c = strchr(fmt, '|');
03365 if (c)
03366 *c = '\0';
03367 if (!strcasecmp(fmt, "wav49"))
03368 strcpy(fmt, "WAV");
03369 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03370 if (msgnum > -1)
03371 make_file(fn, sizeof(fn), dir, msgnum);
03372 else
03373 ast_copy_string(fn, dir, sizeof(fn));
03374
03375
03376 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03377
03378 if (!(f = fopen(full_fn, "w+"))) {
03379 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03380 goto yuck;
03381 }
03382
03383 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03384 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03385 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03386 if (!stmt) {
03387 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03388 ast_odbc_release_obj(obj);
03389 goto yuck;
03390 }
03391 res = SQLFetch(stmt);
03392 if (res == SQL_NO_DATA) {
03393 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03394 ast_odbc_release_obj(obj);
03395 goto yuck;
03396 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03397 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03398 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03399 ast_odbc_release_obj(obj);
03400 goto yuck;
03401 }
03402 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03403 if (fd < 0) {
03404 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03405 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03406 ast_odbc_release_obj(obj);
03407 goto yuck;
03408 }
03409 res = SQLNumResultCols(stmt, &colcount);
03410 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03411 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03412 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03413 ast_odbc_release_obj(obj);
03414 goto yuck;
03415 }
03416 if (f)
03417 fprintf(f, "[message]\n");
03418 for (x = 0; x < colcount; x++) {
03419 rowdata[0] = '\0';
03420 colsize = 0;
03421 collen = sizeof(coltitle);
03422 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03423 &datatype, &colsize, &decimaldigits, &nullable);
03424 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03425 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03426 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03427 ast_odbc_release_obj(obj);
03428 goto yuck;
03429 }
03430 if (!strcasecmp(coltitle, "recording")) {
03431 off_t offset;
03432 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03433 fdlen = colsize2;
03434 if (fd > -1) {
03435 char tmp[1]="";
03436 lseek(fd, fdlen - 1, SEEK_SET);
03437 if (write(fd, tmp, 1) != 1) {
03438 close(fd);
03439 fd = -1;
03440 continue;
03441 }
03442
03443 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03444 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03445 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03446 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03447 ast_odbc_release_obj(obj);
03448 goto yuck;
03449 } else {
03450 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03451 munmap(fdm, CHUNKSIZE);
03452 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03453 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03454 unlink(full_fn);
03455 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03456 ast_odbc_release_obj(obj);
03457 goto yuck;
03458 }
03459 }
03460 }
03461 if (truncate(full_fn, fdlen) < 0) {
03462 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03463 }
03464 }
03465 } else {
03466 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03467 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03468 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03469 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03470 ast_odbc_release_obj(obj);
03471 goto yuck;
03472 }
03473 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03474 fprintf(f, "%s=%s\n", coltitle, rowdata);
03475 }
03476 }
03477 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03478 ast_odbc_release_obj(obj);
03479 } else
03480 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03481 yuck:
03482 if (f)
03483 fclose(f);
03484 if (fd > -1)
03485 close(fd);
03486 return x - 1;
03487 }
03488
03489
03490
03491
03492
03493
03494
03495
03496
03497
03498
03499
03500 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03501 {
03502 int x = 0;
03503 int res;
03504 SQLHSTMT stmt;
03505 char sql[PATH_MAX];
03506 char rowdata[20];
03507 char *argv[] = { dir };
03508 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03509
03510 struct odbc_obj *obj;
03511 obj = ast_odbc_request_obj(odbc_database, 0);
03512 if (obj) {
03513 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
03514
03515 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03516 if (!stmt) {
03517 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03518 ast_odbc_release_obj(obj);
03519 goto yuck;
03520 }
03521 res = SQLFetch(stmt);
03522 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03523 if (res == SQL_NO_DATA) {
03524 ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
03525 } else {
03526 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03527 }
03528
03529 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03530 ast_odbc_release_obj(obj);
03531 goto yuck;
03532 }
03533 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03534 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03535 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03536 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03537 ast_odbc_release_obj(obj);
03538 goto yuck;
03539 }
03540 if (sscanf(rowdata, "%30d", &x) != 1)
03541 ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
03542 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03543 ast_odbc_release_obj(obj);
03544 return x;
03545 } else
03546 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03547 yuck:
03548 return x - 1;
03549 }
03550
03551
03552
03553
03554
03555
03556
03557
03558
03559
03560 static int message_exists(char *dir, int msgnum)
03561 {
03562 int x = 0;
03563 int res;
03564 SQLHSTMT stmt;
03565 char sql[PATH_MAX];
03566 char rowdata[20];
03567 char msgnums[20];
03568 char *argv[] = { dir, msgnums };
03569 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03570
03571 struct odbc_obj *obj;
03572 obj = ast_odbc_request_obj(odbc_database, 0);
03573 if (obj) {
03574 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03575 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03576 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03577 if (!stmt) {
03578 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03579 ast_odbc_release_obj(obj);
03580 goto yuck;
03581 }
03582 res = SQLFetch(stmt);
03583 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03584 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03585 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03586 ast_odbc_release_obj(obj);
03587 goto yuck;
03588 }
03589 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03590 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03591 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03592 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03593 ast_odbc_release_obj(obj);
03594 goto yuck;
03595 }
03596 if (sscanf(rowdata, "%30d", &x) != 1)
03597 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03598 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03599 ast_odbc_release_obj(obj);
03600 } else
03601 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03602 yuck:
03603 return x;
03604 }
03605
03606
03607
03608
03609
03610
03611
03612
03613
03614
03615 static int count_messages(struct ast_vm_user *vmu, char *dir)
03616 {
03617 int x = 0;
03618 int res;
03619 SQLHSTMT stmt;
03620 char sql[PATH_MAX];
03621 char rowdata[20];
03622 char *argv[] = { dir };
03623 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03624
03625 struct odbc_obj *obj;
03626 obj = ast_odbc_request_obj(odbc_database, 0);
03627 if (obj) {
03628 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03629 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03630 if (!stmt) {
03631 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03632 ast_odbc_release_obj(obj);
03633 goto yuck;
03634 }
03635 res = SQLFetch(stmt);
03636 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03637 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03638 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03639 ast_odbc_release_obj(obj);
03640 goto yuck;
03641 }
03642 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03643 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03644 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03645 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03646 ast_odbc_release_obj(obj);
03647 goto yuck;
03648 }
03649 if (sscanf(rowdata, "%30d", &x) != 1)
03650 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03651 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03652 ast_odbc_release_obj(obj);
03653 return x;
03654 } else
03655 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03656 yuck:
03657 return x - 1;
03658
03659 }
03660
03661
03662
03663
03664
03665
03666
03667
03668
03669
03670
03671 static void delete_file(const char *sdir, int smsg)
03672 {
03673 SQLHSTMT stmt;
03674 char sql[PATH_MAX];
03675 char msgnums[20];
03676 char *argv[] = { NULL, msgnums };
03677 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03678 struct odbc_obj *obj;
03679
03680 argv[0] = ast_strdupa(sdir);
03681
03682 obj = ast_odbc_request_obj(odbc_database, 0);
03683 if (obj) {
03684 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03685 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03686 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03687 if (!stmt)
03688 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03689 else
03690 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03691 ast_odbc_release_obj(obj);
03692 } else
03693 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03694 return;
03695 }
03696
03697
03698
03699
03700
03701
03702
03703
03704
03705
03706
03707
03708 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03709 {
03710 SQLHSTMT stmt;
03711 char sql[512];
03712 char msgnums[20];
03713 char msgnumd[20];
03714 struct odbc_obj *obj;
03715 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03716 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03717
03718 delete_file(ddir, dmsg);
03719 obj = ast_odbc_request_obj(odbc_database, 0);
03720 if (obj) {
03721 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03722 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03723 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);
03724 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03725 if (!stmt)
03726 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03727 else
03728 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03729 ast_odbc_release_obj(obj);
03730 } else
03731 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03732 return;
03733 }
03734
03735 struct insert_data {
03736 char *sql;
03737 const char *dir;
03738 const char *msgnums;
03739 void *data;
03740 SQLLEN datalen;
03741 SQLLEN indlen;
03742 const char *context;
03743 const char *macrocontext;
03744 const char *callerid;
03745 const char *origtime;
03746 const char *duration;
03747 const char *mailboxuser;
03748 const char *mailboxcontext;
03749 const char *category;
03750 const char *flag;
03751 };
03752
03753 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03754 {
03755 struct insert_data *data = vdata;
03756 int res;
03757 SQLHSTMT stmt;
03758
03759 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03760 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03761 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03762 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03763 return NULL;
03764 }
03765
03766 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03767 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03768 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03769 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03770 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03771 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03772 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03773 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03774 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03775 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03776 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03777 if (!ast_strlen_zero(data->category)) {
03778 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03779 }
03780 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03781 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03782 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03783 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03784 return NULL;
03785 }
03786
03787 return stmt;
03788 }
03789
03790
03791
03792
03793
03794
03795
03796
03797
03798
03799
03800
03801
03802
03803 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03804 {
03805 int res = 0;
03806 int fd = -1;
03807 void *fdm = MAP_FAILED;
03808 off_t fdlen = -1;
03809 SQLHSTMT stmt;
03810 char sql[PATH_MAX];
03811 char msgnums[20];
03812 char fn[PATH_MAX];
03813 char full_fn[PATH_MAX];
03814 char fmt[80]="";
03815 char *c;
03816 struct ast_config *cfg = NULL;
03817 struct odbc_obj *obj;
03818 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03819 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03820 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03821
03822 delete_file(dir, msgnum);
03823 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03824 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03825 return -1;
03826 }
03827
03828 do {
03829 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03830 c = strchr(fmt, '|');
03831 if (c)
03832 *c = '\0';
03833 if (!strcasecmp(fmt, "wav49"))
03834 strcpy(fmt, "WAV");
03835 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03836 if (msgnum > -1)
03837 make_file(fn, sizeof(fn), dir, msgnum);
03838 else
03839 ast_copy_string(fn, dir, sizeof(fn));
03840 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03841 cfg = ast_config_load(full_fn, config_flags);
03842 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03843 fd = open(full_fn, O_RDWR);
03844 if (fd < 0) {
03845 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03846 res = -1;
03847 break;
03848 }
03849 if (cfg && cfg != CONFIG_STATUS_FILEINVALID) {
03850 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03851 idata.context = "";
03852 }
03853 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03854 idata.macrocontext = "";
03855 }
03856 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03857 idata.callerid = "";
03858 }
03859 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03860 idata.origtime = "";
03861 }
03862 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03863 idata.duration = "";
03864 }
03865 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03866 idata.category = "";
03867 }
03868 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03869 idata.flag = "";
03870 }
03871 }
03872 fdlen = lseek(fd, 0, SEEK_END);
03873 if (fdlen < 0 || lseek(fd, 0, SEEK_SET) < 0) {
03874 ast_log(AST_LOG_WARNING, "Failed to process sound file '%s': %s\n", full_fn, strerror(errno));
03875 res = -1;
03876 break;
03877 }
03878 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03879 if (fdm == MAP_FAILED) {
03880 ast_log(AST_LOG_WARNING, "Memory map failed for sound file '%s'!\n", full_fn);
03881 res = -1;
03882 break;
03883 }
03884 idata.data = fdm;
03885 idata.datalen = idata.indlen = fdlen;
03886
03887 if (!ast_strlen_zero(idata.category))
03888 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03889 else
03890 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03891
03892 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03893 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03894 } else {
03895 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03896 res = -1;
03897 }
03898 } while (0);
03899 if (obj) {
03900 ast_odbc_release_obj(obj);
03901 }
03902 if (cfg)
03903 ast_config_destroy(cfg);
03904 if (fdm != MAP_FAILED)
03905 munmap(fdm, fdlen);
03906 if (fd > -1)
03907 close(fd);
03908 return res;
03909 }
03910
03911
03912
03913
03914
03915
03916
03917
03918
03919
03920
03921
03922
03923
03924 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03925 {
03926 SQLHSTMT stmt;
03927 char sql[PATH_MAX];
03928 char msgnums[20];
03929 char msgnumd[20];
03930 struct odbc_obj *obj;
03931 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03932 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03933
03934 delete_file(ddir, dmsg);
03935 obj = ast_odbc_request_obj(odbc_database, 0);
03936 if (obj) {
03937 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03938 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03939 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03940 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03941 if (!stmt)
03942 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03943 else
03944 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03945 ast_odbc_release_obj(obj);
03946 } else
03947 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03948 return;
03949 }
03950
03951
03952
03953
03954
03955
03956
03957
03958
03959
03960
03961
03962 static int remove_file(char *dir, int msgnum)
03963 {
03964 char fn[PATH_MAX];
03965 char full_fn[PATH_MAX];
03966 char msgnums[80];
03967
03968 if (msgnum > -1) {
03969 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03970 make_file(fn, sizeof(fn), dir, msgnum);
03971 } else
03972 ast_copy_string(fn, dir, sizeof(fn));
03973 ast_filedelete(fn, NULL);
03974 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03975 unlink(full_fn);
03976 return 0;
03977 }
03978 #else
03979 #ifndef IMAP_STORAGE
03980
03981
03982
03983
03984
03985
03986
03987
03988
03989 static int count_messages(struct ast_vm_user *vmu, char *dir)
03990 {
03991
03992 int vmcount = 0;
03993 DIR *vmdir = NULL;
03994 struct dirent *vment = NULL;
03995
03996 if (vm_lock_path(dir))
03997 return ERROR_LOCK_PATH;
03998
03999 if ((vmdir = opendir(dir))) {
04000 while ((vment = readdir(vmdir))) {
04001 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
04002 vmcount++;
04003 }
04004 }
04005 closedir(vmdir);
04006 }
04007 ast_unlock_path(dir);
04008
04009 return vmcount;
04010 }
04011
04012
04013
04014
04015
04016
04017
04018
04019 static void rename_file(char *sfn, char *dfn)
04020 {
04021 char stxt[PATH_MAX];
04022 char dtxt[PATH_MAX];
04023 ast_filerename(sfn, dfn, NULL);
04024 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
04025 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
04026 if (ast_check_realtime("voicemail_data")) {
04027 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
04028 }
04029 rename(stxt, dtxt);
04030 }
04031
04032
04033
04034
04035
04036
04037
04038
04039
04040
04041
04042
04043 static int last_message_index(struct ast_vm_user *vmu, char *dir)
04044 {
04045 int x;
04046 unsigned char map[MAXMSGLIMIT] = "";
04047 DIR *msgdir;
04048 struct dirent *msgdirent;
04049 int msgdirint;
04050 char extension[4];
04051 int stopcount = 0;
04052
04053
04054
04055
04056
04057 if (!(msgdir = opendir(dir))) {
04058 return -1;
04059 }
04060
04061 while ((msgdirent = readdir(msgdir))) {
04062 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
04063 map[msgdirint] = 1;
04064 stopcount++;
04065 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
04066 }
04067 }
04068 closedir(msgdir);
04069
04070 for (x = 0; x < vmu->maxmsg; x++) {
04071 if (map[x] == 1) {
04072 stopcount--;
04073 } else if (map[x] == 0 && !stopcount) {
04074 break;
04075 }
04076 }
04077
04078 return x - 1;
04079 }
04080
04081 #endif
04082 #endif
04083 #ifndef IMAP_STORAGE
04084
04085
04086
04087
04088
04089
04090
04091
04092
04093
04094 static int copy(char *infile, char *outfile)
04095 {
04096 int ifd;
04097 int ofd;
04098 int res;
04099 int len;
04100 char buf[4096];
04101
04102 #ifdef HARDLINK_WHEN_POSSIBLE
04103
04104 if (link(infile, outfile)) {
04105 #endif
04106 if ((ifd = open(infile, O_RDONLY)) < 0) {
04107 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
04108 return -1;
04109 }
04110 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
04111 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
04112 close(ifd);
04113 return -1;
04114 }
04115 do {
04116 len = read(ifd, buf, sizeof(buf));
04117 if (len < 0) {
04118 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
04119 close(ifd);
04120 close(ofd);
04121 unlink(outfile);
04122 } else if (len) {
04123 res = write(ofd, buf, len);
04124 if (errno == ENOMEM || errno == ENOSPC || res != len) {
04125 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
04126 close(ifd);
04127 close(ofd);
04128 unlink(outfile);
04129 }
04130 }
04131 } while (len);
04132 close(ifd);
04133 close(ofd);
04134 return 0;
04135 #ifdef HARDLINK_WHEN_POSSIBLE
04136 } else {
04137
04138 return 0;
04139 }
04140 #endif
04141 }
04142
04143
04144
04145
04146
04147
04148
04149
04150
04151
04152 static void copy_plain_file(char *frompath, char *topath)
04153 {
04154 char frompath2[PATH_MAX], topath2[PATH_MAX];
04155 struct ast_variable *tmp,*var = NULL;
04156 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04157 ast_filecopy(frompath, topath, NULL);
04158 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04159 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04160 if (ast_check_realtime("voicemail_data")) {
04161 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04162
04163 for (tmp = var; tmp; tmp = tmp->next) {
04164 if (!strcasecmp(tmp->name, "origmailbox")) {
04165 origmailbox = tmp->value;
04166 } else if (!strcasecmp(tmp->name, "context")) {
04167 context = tmp->value;
04168 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04169 macrocontext = tmp->value;
04170 } else if (!strcasecmp(tmp->name, "exten")) {
04171 exten = tmp->value;
04172 } else if (!strcasecmp(tmp->name, "priority")) {
04173 priority = tmp->value;
04174 } else if (!strcasecmp(tmp->name, "callerchan")) {
04175 callerchan = tmp->value;
04176 } else if (!strcasecmp(tmp->name, "callerid")) {
04177 callerid = tmp->value;
04178 } else if (!strcasecmp(tmp->name, "origdate")) {
04179 origdate = tmp->value;
04180 } else if (!strcasecmp(tmp->name, "origtime")) {
04181 origtime = tmp->value;
04182 } else if (!strcasecmp(tmp->name, "category")) {
04183 category = tmp->value;
04184 } else if (!strcasecmp(tmp->name, "duration")) {
04185 duration = tmp->value;
04186 }
04187 }
04188 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);
04189 }
04190 copy(frompath2, topath2);
04191 ast_variables_destroy(var);
04192 }
04193 #endif
04194
04195
04196
04197
04198
04199
04200
04201
04202
04203 static int vm_delete(char *file)
04204 {
04205 char *txt;
04206 int txtsize = 0;
04207
04208 txtsize = (strlen(file) + 5)*sizeof(char);
04209 txt = ast_alloca(txtsize);
04210
04211
04212
04213 if (ast_check_realtime("voicemail_data")) {
04214 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04215 }
04216 snprintf(txt, txtsize, "%s.txt", file);
04217 unlink(txt);
04218 return ast_filedelete(file, NULL);
04219 }
04220
04221
04222
04223
04224 static int inbuf(struct baseio *bio, FILE *fi)
04225 {
04226 int l;
04227
04228 if (bio->ateof)
04229 return 0;
04230
04231 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04232 if (ferror(fi))
04233 return -1;
04234
04235 bio->ateof = 1;
04236 return 0;
04237 }
04238
04239 bio->iolen = l;
04240 bio->iocp = 0;
04241
04242 return 1;
04243 }
04244
04245
04246
04247
04248 static int inchar(struct baseio *bio, FILE *fi)
04249 {
04250 if (bio->iocp>=bio->iolen) {
04251 if (!inbuf(bio, fi))
04252 return EOF;
04253 }
04254
04255 return bio->iobuf[bio->iocp++];
04256 }
04257
04258
04259
04260
04261 static int ochar(struct baseio *bio, int c, FILE *so)
04262 {
04263 if (bio->linelength >= BASELINELEN) {
04264 if (fputs(ENDL, so) == EOF) {
04265 return -1;
04266 }
04267
04268 bio->linelength = 0;
04269 }
04270
04271 if (putc(((unsigned char) c), so) == EOF) {
04272 return -1;
04273 }
04274
04275 bio->linelength++;
04276
04277 return 1;
04278 }
04279
04280
04281
04282
04283
04284
04285
04286
04287
04288
04289 static int base_encode(char *filename, FILE *so)
04290 {
04291 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04292 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04293 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04294 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04295 int i, hiteof = 0;
04296 FILE *fi;
04297 struct baseio bio;
04298
04299 memset(&bio, 0, sizeof(bio));
04300 bio.iocp = BASEMAXINLINE;
04301
04302 if (!(fi = fopen(filename, "rb"))) {
04303 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04304 return -1;
04305 }
04306
04307 while (!hiteof){
04308 unsigned char igroup[3], ogroup[4];
04309 int c, n;
04310
04311 memset(igroup, 0, sizeof(igroup));
04312
04313 for (n = 0; n < 3; n++) {
04314 if ((c = inchar(&bio, fi)) == EOF) {
04315 hiteof = 1;
04316 break;
04317 }
04318
04319 igroup[n] = (unsigned char) c;
04320 }
04321
04322 if (n > 0) {
04323 ogroup[0]= dtable[igroup[0] >> 2];
04324 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04325 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04326 ogroup[3]= dtable[igroup[2] & 0x3F];
04327
04328 if (n < 3) {
04329 ogroup[3] = '=';
04330
04331 if (n < 2)
04332 ogroup[2] = '=';
04333 }
04334
04335 for (i = 0; i < 4; i++)
04336 ochar(&bio, ogroup[i], so);
04337 }
04338 }
04339
04340 fclose(fi);
04341
04342 if (fputs(ENDL, so) == EOF) {
04343 return 0;
04344 }
04345
04346 return 1;
04347 }
04348
04349 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)
04350 {
04351 char callerid[256];
04352 char num[12];
04353 char fromdir[256], fromfile[256];
04354 struct ast_config *msg_cfg;
04355 const char *origcallerid, *origtime;
04356 char origcidname[80], origcidnum[80], origdate[80];
04357 int inttime;
04358 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04359
04360
04361 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04362 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04363 snprintf(num, sizeof(num), "%d", msgnum);
04364 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04365 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04366 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04367 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04368 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04369 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04370 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04371 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04372 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04373 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04374
04375
04376 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04377 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04378 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04379 strcat(fromfile, ".txt");
04380 }
04381 if (!(msg_cfg = ast_config_load(fromfile, config_flags))) {
04382 if (option_debug > 0) {
04383 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04384 }
04385 return;
04386 }
04387
04388 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04389 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04390 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04391 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04392 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04393 }
04394
04395 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04396 struct timeval tv = { inttime, };
04397 struct ast_tm tm;
04398 ast_localtime(&tv, &tm, NULL);
04399 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04400 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04401 }
04402 ast_config_destroy(msg_cfg);
04403 }
04404
04405
04406
04407
04408
04409
04410
04411
04412
04413 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04414 {
04415 const char *ptr;
04416
04417
04418 ast_str_set(buf, maxlen, "\"");
04419 for (ptr = from; *ptr; ptr++) {
04420 if (*ptr == '"' || *ptr == '\\') {
04421 ast_str_append(buf, maxlen, "\\%c", *ptr);
04422 } else {
04423 ast_str_append(buf, maxlen, "%c", *ptr);
04424 }
04425 }
04426 ast_str_append(buf, maxlen, "\"");
04427
04428 return ast_str_buffer(*buf);
04429 }
04430
04431
04432
04433
04434
04435 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04436 {
04437 const struct vm_zone *z = NULL;
04438 struct timeval t = ast_tvnow();
04439
04440
04441 if (!ast_strlen_zero(vmu->zonetag)) {
04442
04443 AST_LIST_LOCK(&zones);
04444 AST_LIST_TRAVERSE(&zones, z, list) {
04445 if (!strcmp(z->name, vmu->zonetag))
04446 break;
04447 }
04448 AST_LIST_UNLOCK(&zones);
04449 }
04450 ast_localtime(&t, tm, z ? z->timezone : NULL);
04451 return tm;
04452 }
04453
04454
04455
04456
04457
04458 static int check_mime(const char *str)
04459 {
04460 for (; *str; str++) {
04461 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04462 return 1;
04463 }
04464 }
04465 return 0;
04466 }
04467
04468
04469
04470
04471
04472
04473
04474
04475
04476
04477
04478
04479
04480
04481
04482
04483
04484
04485 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04486 {
04487 struct ast_str *tmp = ast_str_alloca(80);
04488 int first_section = 1;
04489
04490 ast_str_reset(*end);
04491 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04492 for (; *start; start++) {
04493 int need_encoding = 0;
04494 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04495 need_encoding = 1;
04496 }
04497 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04498 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04499 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04500 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04501
04502 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04503 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04504 first_section = 0;
04505 }
04506 if (need_encoding && *start == ' ') {
04507 ast_str_append(&tmp, -1, "_");
04508 } else if (need_encoding) {
04509 ast_str_append(&tmp, -1, "=%hhX", *start);
04510 } else {
04511 ast_str_append(&tmp, -1, "%c", *start);
04512 }
04513 }
04514 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04515 return ast_str_buffer(*end);
04516 }
04517
04518
04519
04520
04521
04522
04523
04524
04525
04526
04527
04528
04529
04530
04531
04532
04533
04534
04535
04536
04537
04538
04539
04540
04541 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)
04542 {
04543 char date[256];
04544 char host[MAXHOSTNAMELEN] = "";
04545 char who[256];
04546 char bound[256];
04547 char dur[256];
04548 struct ast_tm tm;
04549 char enc_cidnum[256] = "", enc_cidname[256] = "";
04550 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04551 char *greeting_attachment;
04552 char filename[256];
04553
04554 if (!str1 || !str2) {
04555 ast_free(str1);
04556 ast_free(str2);
04557 return;
04558 }
04559
04560 if (cidnum) {
04561 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04562 }
04563 if (cidname) {
04564 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04565 }
04566 gethostname(host, sizeof(host) - 1);
04567
04568 if (strchr(srcemail, '@')) {
04569 ast_copy_string(who, srcemail, sizeof(who));
04570 } else {
04571 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04572 }
04573
04574 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04575 if (greeting_attachment) {
04576 *greeting_attachment++ = '\0';
04577 }
04578
04579 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04580 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04581 fprintf(p, "Date: %s" ENDL, date);
04582
04583
04584 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04585
04586 if (!ast_strlen_zero(fromstring)) {
04587 struct ast_channel *ast;
04588 if ((ast = ast_dummy_channel_alloc())) {
04589 char *ptr;
04590 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04591 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04592
04593 if (check_mime(ast_str_buffer(str1))) {
04594 int first_line = 1;
04595 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04596 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04597 *ptr = '\0';
04598 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04599 first_line = 0;
04600
04601 ast_str_set(&str2, 0, "%s", ptr + 1);
04602 }
04603 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04604 } else {
04605 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04606 }
04607 ast = ast_channel_unref(ast);
04608 } else {
04609 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04610 }
04611 } else {
04612 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04613 }
04614
04615 if (check_mime(vmu->fullname)) {
04616 int first_line = 1;
04617 char *ptr;
04618 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04619 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04620 *ptr = '\0';
04621 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04622 first_line = 0;
04623
04624 ast_str_set(&str2, 0, "%s", ptr + 1);
04625 }
04626 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04627 } else {
04628 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04629 }
04630
04631 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04632 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04633 struct ast_channel *ast;
04634 if ((ast = ast_dummy_channel_alloc())) {
04635 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04636 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04637 if (check_mime(ast_str_buffer(str1))) {
04638 int first_line = 1;
04639 char *ptr;
04640 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04641 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04642 *ptr = '\0';
04643 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04644 first_line = 0;
04645
04646 ast_str_set(&str2, 0, "%s", ptr + 1);
04647 }
04648 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04649 } else {
04650 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04651 }
04652 ast = ast_channel_unref(ast);
04653 } else {
04654 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04655 }
04656 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04657 if (ast_strlen_zero(flag)) {
04658 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04659 } else {
04660 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04661 }
04662 } else {
04663 if (ast_strlen_zero(flag)) {
04664 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04665 } else {
04666 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04667 }
04668 }
04669
04670 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1,
04671 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04672 if (imap) {
04673
04674 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04675
04676 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04677 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04678 #ifdef IMAP_STORAGE
04679 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04680 #else
04681 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04682 #endif
04683
04684 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04685 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04686 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04687 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04688 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04689 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04690 if (!ast_strlen_zero(category)) {
04691 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04692 } else {
04693 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04694 }
04695 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04696 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04697 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04698 }
04699 if (!ast_strlen_zero(cidnum)) {
04700 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04701 }
04702 if (!ast_strlen_zero(cidname)) {
04703 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04704 }
04705 fprintf(p, "MIME-Version: 1.0" ENDL);
04706 if (attach_user_voicemail) {
04707
04708 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox,
04709 (int) getpid(), (unsigned int) ast_random());
04710
04711 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04712 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04713 fprintf(p, "--%s" ENDL, bound);
04714 }
04715 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04716 if (emailbody || vmu->emailbody) {
04717 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04718 struct ast_channel *ast;
04719 if ((ast = ast_dummy_channel_alloc())) {
04720 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04721 ast_str_substitute_variables(&str1, 0, ast, e_body);
04722 #ifdef IMAP_STORAGE
04723 {
04724
04725 char *line = ast_str_buffer(str1), *next;
04726 do {
04727
04728 if ((next = strchr(line, '\n'))) {
04729 *next++ = '\0';
04730 }
04731 fprintf(p, "%s" ENDL, line);
04732 line = next;
04733 } while (!ast_strlen_zero(line));
04734 }
04735 #else
04736 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04737 #endif
04738 ast = ast_channel_unref(ast);
04739 } else {
04740 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04741 }
04742 } else if (msgnum > -1) {
04743 if (strcmp(vmu->mailbox, mailbox)) {
04744
04745 struct ast_config *msg_cfg;
04746 const char *v;
04747 int inttime;
04748 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04749 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04750
04751 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04752 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04753 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04754 strcat(fromfile, ".txt");
04755 }
04756 if ((msg_cfg = ast_config_load(fromfile, config_flags))) {
04757 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04758 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04759 }
04760
04761
04762
04763 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04764 struct timeval tv = { inttime, };
04765 struct ast_tm tm;
04766 ast_localtime(&tv, &tm, NULL);
04767 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04768 }
04769 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04770 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04771 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04772 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04773 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04774 date, origcallerid, origdate);
04775 ast_config_destroy(msg_cfg);
04776 } else {
04777 goto plain_message;
04778 }
04779 } else {
04780 plain_message:
04781 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04782 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04783 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04784 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04785 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04786 }
04787 } else {
04788 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04789 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04790 }
04791
04792 if (imap || attach_user_voicemail) {
04793 if (!ast_strlen_zero(attach2)) {
04794 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04795 ast_debug(5, "creating second attachment filename %s\n", filename);
04796 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04797 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04798 ast_debug(5, "creating attachment filename %s\n", filename);
04799 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04800 } else {
04801 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04802 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04803 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04804 }
04805 }
04806 ast_free(str1);
04807 ast_free(str2);
04808 }
04809
04810 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)
04811 {
04812 char tmpdir[256], newtmp[256];
04813 char fname[256];
04814 char tmpcmd[256];
04815 int tmpfd = -1;
04816 int soxstatus = 0;
04817
04818
04819 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04820
04821 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04822 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04823 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04824 tmpfd = mkstemp(newtmp);
04825 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04826 ast_debug(3, "newtmp: %s\n", newtmp);
04827 if (tmpfd > -1) {
04828 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04829 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04830 attach = newtmp;
04831 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04832 } else {
04833 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04834 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04835 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04836 }
04837 }
04838 }
04839 fprintf(p, "--%s" ENDL, bound);
04840 if (msgnum > -1)
04841 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04842 else
04843 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04844 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04845 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04846 if (msgnum > -1)
04847 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04848 else
04849 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04850 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04851 base_encode(fname, p);
04852 if (last)
04853 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04854 if (tmpfd > -1) {
04855 if (soxstatus == 0) {
04856 unlink(fname);
04857 }
04858 close(tmpfd);
04859 unlink(newtmp);
04860 }
04861 return 0;
04862 }
04863
04864 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)
04865 {
04866 FILE *p = NULL;
04867 char tmp[80] = "/tmp/astmail-XXXXXX";
04868 char tmp2[256];
04869 char *stringp;
04870
04871 if (vmu && ast_strlen_zero(vmu->email)) {
04872 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04873 return(0);
04874 }
04875
04876
04877 format = ast_strdupa(format);
04878 stringp = format;
04879 strsep(&stringp, "|");
04880
04881 if (!strcmp(format, "wav49"))
04882 format = "WAV";
04883 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));
04884
04885
04886 if ((p = vm_mkftemp(tmp)) == NULL) {
04887 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04888 return -1;
04889 } else {
04890 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04891 fclose(p);
04892 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04893 ast_safe_system(tmp2);
04894 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04895 }
04896 return 0;
04897 }
04898
04899 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)
04900 {
04901 char enc_cidnum[256], enc_cidname[256];
04902 char date[256];
04903 char host[MAXHOSTNAMELEN] = "";
04904 char who[256];
04905 char dur[PATH_MAX];
04906 char tmp[80] = "/tmp/astmail-XXXXXX";
04907 char tmp2[PATH_MAX];
04908 struct ast_tm tm;
04909 FILE *p;
04910 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04911
04912 if (!str1 || !str2) {
04913 ast_free(str1);
04914 ast_free(str2);
04915 return -1;
04916 }
04917
04918 if (cidnum) {
04919 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04920 }
04921 if (cidname) {
04922 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04923 }
04924
04925 if ((p = vm_mkftemp(tmp)) == NULL) {
04926 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04927 ast_free(str1);
04928 ast_free(str2);
04929 return -1;
04930 }
04931 gethostname(host, sizeof(host)-1);
04932 if (strchr(srcemail, '@')) {
04933 ast_copy_string(who, srcemail, sizeof(who));
04934 } else {
04935 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04936 }
04937 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04938 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04939 fprintf(p, "Date: %s\n", date);
04940
04941
04942 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04943
04944 if (!ast_strlen_zero(pagerfromstring)) {
04945 struct ast_channel *ast;
04946 if ((ast = ast_dummy_channel_alloc())) {
04947 char *ptr;
04948 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04949 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04950
04951 if (check_mime(ast_str_buffer(str1))) {
04952 int first_line = 1;
04953 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04954 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04955 *ptr = '\0';
04956 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04957 first_line = 0;
04958
04959 ast_str_set(&str2, 0, "%s", ptr + 1);
04960 }
04961 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04962 } else {
04963 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04964 }
04965 ast = ast_channel_unref(ast);
04966 } else {
04967 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04968 }
04969 } else {
04970 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04971 }
04972
04973 if (check_mime(vmu->fullname)) {
04974 int first_line = 1;
04975 char *ptr;
04976 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
04977 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04978 *ptr = '\0';
04979 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04980 first_line = 0;
04981
04982 ast_str_set(&str2, 0, "%s", ptr + 1);
04983 }
04984 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
04985 } else {
04986 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
04987 }
04988
04989 if (!ast_strlen_zero(pagersubject)) {
04990 struct ast_channel *ast;
04991 if ((ast = ast_dummy_channel_alloc())) {
04992 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04993 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
04994 if (check_mime(ast_str_buffer(str1))) {
04995 int first_line = 1;
04996 char *ptr;
04997 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04998 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04999 *ptr = '\0';
05000 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05001 first_line = 0;
05002
05003 ast_str_set(&str2, 0, "%s", ptr + 1);
05004 }
05005 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05006 } else {
05007 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
05008 }
05009 ast = ast_channel_unref(ast);
05010 } else {
05011 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05012 }
05013 } else {
05014 if (ast_strlen_zero(flag)) {
05015 fprintf(p, "Subject: New VM\n\n");
05016 } else {
05017 fprintf(p, "Subject: New %s VM\n\n", flag);
05018 }
05019 }
05020
05021 if (pagerbody) {
05022 struct ast_channel *ast;
05023 if ((ast = ast_dummy_channel_alloc())) {
05024 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05025 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
05026 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
05027 ast = ast_channel_unref(ast);
05028 } else {
05029 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05030 }
05031 } else {
05032 fprintf(p, "New %s long %s msg in box %s\n"
05033 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
05034 }
05035
05036 fclose(p);
05037 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
05038 ast_safe_system(tmp2);
05039 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
05040 ast_free(str1);
05041 ast_free(str2);
05042 return 0;
05043 }
05044
05045
05046
05047
05048
05049
05050
05051
05052
05053
05054 static int get_date(char *s, int len)
05055 {
05056 struct ast_tm tm;
05057 struct timeval t = ast_tvnow();
05058
05059 ast_localtime(&t, &tm, "UTC");
05060
05061 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
05062 }
05063
05064 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
05065 {
05066 int res;
05067 char fn[PATH_MAX];
05068 char dest[PATH_MAX];
05069
05070 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
05071
05072 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
05073 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
05074 return -1;
05075 }
05076
05077 RETRIEVE(fn, -1, ext, context);
05078 if (ast_fileexists(fn, NULL, NULL) > 0) {
05079 res = ast_stream_and_wait(chan, fn, ecodes);
05080 if (res) {
05081 DISPOSE(fn, -1);
05082 return res;
05083 }
05084 } else {
05085
05086 DISPOSE(fn, -1);
05087 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
05088 if (res)
05089 return res;
05090 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
05091 if (res)
05092 return res;
05093 }
05094 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
05095 return res;
05096 }
05097
05098 static void free_zone(struct vm_zone *z)
05099 {
05100 ast_free(z);
05101 }
05102
05103 #ifdef ODBC_STORAGE
05104 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05105 {
05106 int x = -1;
05107 int res;
05108 SQLHSTMT stmt = NULL;
05109 char sql[PATH_MAX];
05110 char rowdata[20];
05111 char tmp[PATH_MAX] = "";
05112 struct odbc_obj *obj = NULL;
05113 char *context;
05114 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05115
05116 if (newmsgs)
05117 *newmsgs = 0;
05118 if (oldmsgs)
05119 *oldmsgs = 0;
05120 if (urgentmsgs)
05121 *urgentmsgs = 0;
05122
05123
05124 if (ast_strlen_zero(mailbox))
05125 return 0;
05126
05127 ast_copy_string(tmp, mailbox, sizeof(tmp));
05128
05129 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
05130 int u, n, o;
05131 char *next, *remaining = tmp;
05132 while ((next = strsep(&remaining, " ,"))) {
05133 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05134 return -1;
05135 }
05136 if (urgentmsgs) {
05137 *urgentmsgs += u;
05138 }
05139 if (newmsgs) {
05140 *newmsgs += n;
05141 }
05142 if (oldmsgs) {
05143 *oldmsgs += o;
05144 }
05145 }
05146 return 0;
05147 }
05148
05149 context = strchr(tmp, '@');
05150 if (context) {
05151 *context = '\0';
05152 context++;
05153 } else
05154 context = "default";
05155
05156 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05157 do {
05158 if (newmsgs) {
05159 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05160 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05161 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05162 break;
05163 }
05164 res = SQLFetch(stmt);
05165 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05166 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05167 break;
05168 }
05169 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05170 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05171 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05172 break;
05173 }
05174 *newmsgs = atoi(rowdata);
05175 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05176 }
05177
05178 if (oldmsgs) {
05179 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05180 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05181 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05182 break;
05183 }
05184 res = SQLFetch(stmt);
05185 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05186 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05187 break;
05188 }
05189 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05190 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05191 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05192 break;
05193 }
05194 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05195 *oldmsgs = atoi(rowdata);
05196 }
05197
05198 if (urgentmsgs) {
05199 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05200 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05201 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05202 break;
05203 }
05204 res = SQLFetch(stmt);
05205 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05206 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05207 break;
05208 }
05209 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05210 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05211 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05212 break;
05213 }
05214 *urgentmsgs = atoi(rowdata);
05215 }
05216
05217 x = 0;
05218 } while (0);
05219 } else {
05220 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05221 }
05222
05223 if (stmt) {
05224 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05225 }
05226 if (obj) {
05227 ast_odbc_release_obj(obj);
05228 }
05229 return x;
05230 }
05231
05232
05233
05234
05235
05236
05237
05238
05239
05240
05241 static int messagecount(const char *context, const char *mailbox, const char *folder)
05242 {
05243 struct odbc_obj *obj = NULL;
05244 int nummsgs = 0;
05245 int res;
05246 SQLHSTMT stmt = NULL;
05247 char sql[PATH_MAX];
05248 char rowdata[20];
05249 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05250 if (!folder)
05251 folder = "INBOX";
05252
05253 if (ast_strlen_zero(mailbox))
05254 return 0;
05255
05256 obj = ast_odbc_request_obj(odbc_database, 0);
05257 if (obj) {
05258 if (!strcmp(folder, "INBOX")) {
05259 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);
05260 } else {
05261 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05262 }
05263 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05264 if (!stmt) {
05265 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05266 goto yuck;
05267 }
05268 res = SQLFetch(stmt);
05269 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05270 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05271 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05272 goto yuck;
05273 }
05274 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05275 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05276 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05277 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05278 goto yuck;
05279 }
05280 nummsgs = atoi(rowdata);
05281 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05282 } else
05283 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05284
05285 yuck:
05286 if (obj)
05287 ast_odbc_release_obj(obj);
05288 return nummsgs;
05289 }
05290
05291
05292
05293
05294
05295
05296
05297
05298
05299 static int has_voicemail(const char *mailbox, const char *folder)
05300 {
05301 char tmp[256], *tmp2 = tmp, *box, *context;
05302 ast_copy_string(tmp, mailbox, sizeof(tmp));
05303 while ((context = box = strsep(&tmp2, ",&"))) {
05304 strsep(&context, "@");
05305 if (ast_strlen_zero(context))
05306 context = "default";
05307 if (messagecount(context, box, folder))
05308 return 1;
05309 }
05310 return 0;
05311 }
05312 #endif
05313 #ifndef IMAP_STORAGE
05314
05315
05316
05317
05318
05319
05320
05321
05322
05323
05324
05325
05326
05327
05328
05329
05330 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)
05331 {
05332 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05333 const char *frombox = mbox(vmu, imbox);
05334 const char *userfolder;
05335 int recipmsgnum;
05336 int res = 0;
05337
05338 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05339
05340 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05341 userfolder = "Urgent";
05342 } else {
05343 userfolder = "INBOX";
05344 }
05345
05346 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05347
05348 if (!dir)
05349 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05350 else
05351 ast_copy_string(fromdir, dir, sizeof(fromdir));
05352
05353 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05354 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05355
05356 if (vm_lock_path(todir))
05357 return ERROR_LOCK_PATH;
05358
05359 recipmsgnum = last_message_index(recip, todir) + 1;
05360 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05361 make_file(topath, sizeof(topath), todir, recipmsgnum);
05362 #ifndef ODBC_STORAGE
05363 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05364 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05365 } else {
05366 #endif
05367
05368
05369
05370 copy_plain_file(frompath, topath);
05371 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05372 vm_delete(topath);
05373 #ifndef ODBC_STORAGE
05374 }
05375 #endif
05376 } else {
05377 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05378 res = -1;
05379 }
05380 ast_unlock_path(todir);
05381 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05382 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05383 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05384 flag);
05385
05386 return res;
05387 }
05388 #endif
05389 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05390
05391 static int messagecount(const char *context, const char *mailbox, const char *folder)
05392 {
05393 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05394 }
05395
05396 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05397 {
05398 DIR *dir;
05399 struct dirent *de;
05400 char fn[256];
05401 int ret = 0;
05402
05403
05404 if (ast_strlen_zero(mailbox))
05405 return 0;
05406
05407 if (ast_strlen_zero(folder))
05408 folder = "INBOX";
05409 if (ast_strlen_zero(context))
05410 context = "default";
05411
05412 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05413
05414 if (!(dir = opendir(fn)))
05415 return 0;
05416
05417 while ((de = readdir(dir))) {
05418 if (!strncasecmp(de->d_name, "msg", 3)) {
05419 if (shortcircuit) {
05420 ret = 1;
05421 break;
05422 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05423 ret++;
05424 }
05425 }
05426 }
05427
05428 closedir(dir);
05429
05430 return ret;
05431 }
05432
05433
05434
05435
05436
05437
05438
05439
05440
05441
05442 static int has_voicemail(const char *mailbox, const char *folder)
05443 {
05444 char tmp[256], *tmp2 = tmp, *box, *context;
05445 ast_copy_string(tmp, mailbox, sizeof(tmp));
05446 if (ast_strlen_zero(folder)) {
05447 folder = "INBOX";
05448 }
05449 while ((box = strsep(&tmp2, ",&"))) {
05450 if ((context = strchr(box, '@')))
05451 *context++ = '\0';
05452 else
05453 context = "default";
05454 if (__has_voicemail(context, box, folder, 1))
05455 return 1;
05456
05457 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05458 return 1;
05459 }
05460 }
05461 return 0;
05462 }
05463
05464
05465 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05466 {
05467 char tmp[256];
05468 char *context;
05469
05470
05471 if (ast_strlen_zero(mailbox))
05472 return 0;
05473
05474 if (newmsgs)
05475 *newmsgs = 0;
05476 if (oldmsgs)
05477 *oldmsgs = 0;
05478 if (urgentmsgs)
05479 *urgentmsgs = 0;
05480
05481 if (strchr(mailbox, ',')) {
05482 int tmpnew, tmpold, tmpurgent;
05483 char *mb, *cur;
05484
05485 ast_copy_string(tmp, mailbox, sizeof(tmp));
05486 mb = tmp;
05487 while ((cur = strsep(&mb, ", "))) {
05488 if (!ast_strlen_zero(cur)) {
05489 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05490 return -1;
05491 else {
05492 if (newmsgs)
05493 *newmsgs += tmpnew;
05494 if (oldmsgs)
05495 *oldmsgs += tmpold;
05496 if (urgentmsgs)
05497 *urgentmsgs += tmpurgent;
05498 }
05499 }
05500 }
05501 return 0;
05502 }
05503
05504 ast_copy_string(tmp, mailbox, sizeof(tmp));
05505
05506 if ((context = strchr(tmp, '@')))
05507 *context++ = '\0';
05508 else
05509 context = "default";
05510
05511 if (newmsgs)
05512 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05513 if (oldmsgs)
05514 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05515 if (urgentmsgs)
05516 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05517
05518 return 0;
05519 }
05520
05521 #endif
05522
05523
05524 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05525 {
05526 int urgentmsgs = 0;
05527 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05528 if (newmsgs) {
05529 *newmsgs += urgentmsgs;
05530 }
05531 return res;
05532 }
05533
05534 static void run_externnotify(char *context, char *extension, const char *flag)
05535 {
05536 char arguments[255];
05537 char ext_context[256] = "";
05538 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05539 struct ast_smdi_mwi_message *mwi_msg;
05540
05541 if (!ast_strlen_zero(context))
05542 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05543 else
05544 ast_copy_string(ext_context, extension, sizeof(ext_context));
05545
05546 if (smdi_iface) {
05547 if (ast_app_has_voicemail(ext_context, NULL))
05548 ast_smdi_mwi_set(smdi_iface, extension);
05549 else
05550 ast_smdi_mwi_unset(smdi_iface, extension);
05551
05552 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05553 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05554 if (!strncmp(mwi_msg->cause, "INV", 3))
05555 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05556 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05557 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05558 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05559 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05560 } else {
05561 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05562 }
05563 }
05564
05565 if (!ast_strlen_zero(externnotify)) {
05566 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05567 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05568 } else {
05569 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &", externnotify, context, extension, newvoicemails, oldvoicemails, urgentvoicemails);
05570 ast_debug(1, "Executing %s\n", arguments);
05571 ast_safe_system(arguments);
05572 }
05573 }
05574 }
05575
05576
05577
05578
05579
05580
05581 struct leave_vm_options {
05582 unsigned int flags;
05583 signed char record_gain;
05584 char *exitcontext;
05585 };
05586
05587
05588
05589
05590
05591
05592
05593
05594
05595
05596
05597 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05598 {
05599 #ifdef IMAP_STORAGE
05600 int newmsgs, oldmsgs;
05601 #else
05602 char urgdir[PATH_MAX];
05603 #endif
05604 char txtfile[PATH_MAX];
05605 char tmptxtfile[PATH_MAX];
05606 struct vm_state *vms = NULL;
05607 char callerid[256];
05608 FILE *txt;
05609 char date[256];
05610 int txtdes;
05611 int res = 0;
05612 int msgnum;
05613 int duration = 0;
05614 int sound_duration = 0;
05615 int ausemacro = 0;
05616 int ousemacro = 0;
05617 int ouseexten = 0;
05618 char tmpdur[16];
05619 char priority[16];
05620 char origtime[16];
05621 char dir[PATH_MAX];
05622 char tmpdir[PATH_MAX];
05623 char fn[PATH_MAX];
05624 char prefile[PATH_MAX] = "";
05625 char tempfile[PATH_MAX] = "";
05626 char ext_context[256] = "";
05627 char fmt[80];
05628 char *context;
05629 char ecodes[17] = "#";
05630 struct ast_str *tmp = ast_str_create(16);
05631 char *tmpptr;
05632 struct ast_vm_user *vmu;
05633 struct ast_vm_user svm;
05634 const char *category = NULL;
05635 const char *code;
05636 const char *alldtmf = "0123456789ABCD*#";
05637 char flag[80];
05638
05639 if (!tmp) {
05640 return -1;
05641 }
05642
05643 ast_str_set(&tmp, 0, "%s", ext);
05644 ext = ast_str_buffer(tmp);
05645 if ((context = strchr(ext, '@'))) {
05646 *context++ = '\0';
05647 tmpptr = strchr(context, '&');
05648 } else {
05649 tmpptr = strchr(ext, '&');
05650 }
05651
05652 if (tmpptr)
05653 *tmpptr++ = '\0';
05654
05655 ast_channel_lock(chan);
05656 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05657 category = ast_strdupa(category);
05658 }
05659 ast_channel_unlock(chan);
05660
05661 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05662 ast_copy_string(flag, "Urgent", sizeof(flag));
05663 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05664 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05665 } else {
05666 flag[0] = '\0';
05667 }
05668
05669 ast_debug(3, "Before find_user\n");
05670 if (!(vmu = find_user(&svm, context, ext))) {
05671 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05672 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05673 ast_free(tmp);
05674 return res;
05675 }
05676
05677 if (strcmp(vmu->context, "default"))
05678 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05679 else
05680 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05681
05682
05683
05684
05685
05686
05687 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05688 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05689 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05690 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05691 }
05692
05693
05694
05695
05696 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05697 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05698 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05699 ast_free(tmp);
05700 return -1;
05701 }
05702 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05703 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05704 ast_copy_string(prefile, tempfile, sizeof(prefile));
05705
05706 DISPOSE(tempfile, -1);
05707
05708 #ifndef IMAP_STORAGE
05709 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05710 #else
05711 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05712 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05713 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05714 }
05715 #endif
05716
05717
05718 if (ast_test_flag(vmu, VM_OPERATOR)) {
05719 if (!ast_strlen_zero(vmu->exit)) {
05720 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05721 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05722 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05723 ouseexten = 1;
05724 }
05725 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05726 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05727 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05728 ouseexten = 1;
05729 } else if (!ast_strlen_zero(chan->macrocontext)
05730 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05731 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05732 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05733 ousemacro = 1;
05734 }
05735 }
05736
05737 if (!ast_strlen_zero(vmu->exit)) {
05738 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05739 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05740 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05741 }
05742 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05743 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05744 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05745 } else if (!ast_strlen_zero(chan->macrocontext)
05746 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05747 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05748 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05749 ausemacro = 1;
05750 }
05751
05752 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05753 for (code = alldtmf; *code; code++) {
05754 char e[2] = "";
05755 e[0] = *code;
05756 if (strchr(ecodes, e[0]) == NULL
05757 && ast_canmatch_extension(chan,
05758 (!ast_strlen_zero(options->exitcontext) ? options->exitcontext : chan->context),
05759 e, 1, S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05760 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05761 }
05762 }
05763 }
05764
05765
05766 if (!ast_strlen_zero(prefile)) {
05767 #ifdef ODBC_STORAGE
05768 int success =
05769 #endif
05770 RETRIEVE(prefile, -1, ext, context);
05771 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05772 if (ast_streamfile(chan, prefile, chan->language) > -1)
05773 res = ast_waitstream(chan, ecodes);
05774 #ifdef ODBC_STORAGE
05775 if (success == -1) {
05776
05777 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05778 store_file(prefile, vmu->mailbox, vmu->context, -1);
05779 }
05780 #endif
05781 } else {
05782 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05783 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05784 }
05785 DISPOSE(prefile, -1);
05786 if (res < 0) {
05787 ast_debug(1, "Hang up during prefile playback\n");
05788 free_user(vmu);
05789 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05790 ast_free(tmp);
05791 return -1;
05792 }
05793 }
05794 if (res == '#') {
05795
05796 ast_set_flag(options, OPT_SILENT);
05797 res = 0;
05798 }
05799
05800 if (vmu->maxmsg == 0) {
05801 if (option_debug > 2)
05802 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05803 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05804 goto leave_vm_out;
05805 }
05806 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05807 res = ast_stream_and_wait(chan, INTRO, ecodes);
05808 if (res == '#') {
05809 ast_set_flag(options, OPT_SILENT);
05810 res = 0;
05811 }
05812 }
05813 if (res > 0)
05814 ast_stopstream(chan);
05815
05816
05817 if (res == '*') {
05818 chan->exten[0] = 'a';
05819 chan->exten[1] = '\0';
05820 if (!ast_strlen_zero(vmu->exit)) {
05821 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05822 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05823 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05824 }
05825 chan->priority = 0;
05826 free_user(vmu);
05827 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05828 ast_free(tmp);
05829 return 0;
05830 }
05831
05832
05833 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05834 transfer:
05835 if (ouseexten || ousemacro) {
05836 chan->exten[0] = 'o';
05837 chan->exten[1] = '\0';
05838 if (!ast_strlen_zero(vmu->exit)) {
05839 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05840 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05841 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05842 }
05843 ast_play_and_wait(chan, "transfer");
05844 chan->priority = 0;
05845 free_user(vmu);
05846 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05847 }
05848 ast_free(tmp);
05849 return OPERATOR_EXIT;
05850 }
05851
05852
05853 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05854 if (!ast_strlen_zero(options->exitcontext)) {
05855 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05856 }
05857 free_user(vmu);
05858 ast_free(tmp);
05859 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05860 return res;
05861 }
05862
05863 if (res < 0) {
05864 free_user(vmu);
05865 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05866 ast_free(tmp);
05867 return -1;
05868 }
05869
05870 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05871 if (!ast_strlen_zero(fmt)) {
05872 msgnum = 0;
05873
05874 #ifdef IMAP_STORAGE
05875
05876
05877 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05878 if (res < 0) {
05879 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05880 ast_free(tmp);
05881 return -1;
05882 }
05883 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05884
05885
05886
05887
05888 if (!(vms = create_vm_state_from_user(vmu))) {
05889 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05890 ast_free(tmp);
05891 return -1;
05892 }
05893 }
05894 vms->newmessages++;
05895
05896
05897 msgnum = newmsgs + oldmsgs;
05898 ast_debug(3, "Messagecount set to %d\n", msgnum);
05899 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05900
05901 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05902
05903 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05904 goto leave_vm_out;
05905 }
05906 #else
05907 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05908 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05909 if (!res)
05910 res = ast_waitstream(chan, "");
05911 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05912 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05913 inprocess_count(vmu->mailbox, vmu->context, -1);
05914 goto leave_vm_out;
05915 }
05916
05917 #endif
05918 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05919 txtdes = mkstemp(tmptxtfile);
05920 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05921 if (txtdes < 0) {
05922 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05923 if (!res)
05924 res = ast_waitstream(chan, "");
05925 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05926 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05927 inprocess_count(vmu->mailbox, vmu->context, -1);
05928 goto leave_vm_out;
05929 }
05930
05931
05932 if (res >= 0) {
05933
05934 res = ast_stream_and_wait(chan, "beep", "");
05935 }
05936
05937
05938 if (ast_check_realtime("voicemail_data")) {
05939 snprintf(priority, sizeof(priority), "%d", chan->priority);
05940 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05941 get_date(date, sizeof(date));
05942 ast_callerid_merge(callerid, sizeof(callerid),
05943 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05944 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05945 "Unknown");
05946 ast_store_realtime("voicemail_data",
05947 "origmailbox", ext,
05948 "context", chan->context,
05949 "macrocontext", chan->macrocontext,
05950 "exten", chan->exten,
05951 "priority", priority,
05952 "callerchan", chan->name,
05953 "callerid", callerid,
05954 "origdate", date,
05955 "origtime", origtime,
05956 "category", S_OR(category, ""),
05957 "filename", tmptxtfile,
05958 SENTINEL);
05959 }
05960
05961
05962 txt = fdopen(txtdes, "w+");
05963 if (txt) {
05964 get_date(date, sizeof(date));
05965 ast_callerid_merge(callerid, sizeof(callerid),
05966 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05967 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05968 "Unknown");
05969 fprintf(txt,
05970 ";\n"
05971 "; Message Information file\n"
05972 ";\n"
05973 "[message]\n"
05974 "origmailbox=%s\n"
05975 "context=%s\n"
05976 "macrocontext=%s\n"
05977 "exten=%s\n"
05978 "rdnis=%s\n"
05979 "priority=%d\n"
05980 "callerchan=%s\n"
05981 "callerid=%s\n"
05982 "origdate=%s\n"
05983 "origtime=%ld\n"
05984 "category=%s\n",
05985 ext,
05986 chan->context,
05987 chan->macrocontext,
05988 chan->exten,
05989 S_COR(chan->redirecting.from.number.valid,
05990 chan->redirecting.from.number.str, "unknown"),
05991 chan->priority,
05992 chan->name,
05993 callerid,
05994 date, (long) time(NULL),
05995 category ? category : "");
05996 } else {
05997 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
05998 inprocess_count(vmu->mailbox, vmu->context, -1);
05999 if (ast_check_realtime("voicemail_data")) {
06000 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06001 }
06002 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
06003 goto leave_vm_out;
06004 }
06005 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag);
06006
06007 if (txt) {
06008 fprintf(txt, "flag=%s\n", flag);
06009 if (sound_duration < vmu->minsecs) {
06010 fclose(txt);
06011 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
06012 ast_filedelete(tmptxtfile, NULL);
06013 unlink(tmptxtfile);
06014 if (ast_check_realtime("voicemail_data")) {
06015 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06016 }
06017 inprocess_count(vmu->mailbox, vmu->context, -1);
06018 } else {
06019 fprintf(txt, "duration=%d\n", duration);
06020 fclose(txt);
06021 if (vm_lock_path(dir)) {
06022 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
06023
06024 ast_filedelete(tmptxtfile, NULL);
06025 unlink(tmptxtfile);
06026 inprocess_count(vmu->mailbox, vmu->context, -1);
06027 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
06028 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
06029 unlink(tmptxtfile);
06030 ast_unlock_path(dir);
06031 inprocess_count(vmu->mailbox, vmu->context, -1);
06032 if (ast_check_realtime("voicemail_data")) {
06033 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06034 }
06035 } else {
06036 #ifndef IMAP_STORAGE
06037 msgnum = last_message_index(vmu, dir) + 1;
06038 #endif
06039 make_file(fn, sizeof(fn), dir, msgnum);
06040
06041
06042 #ifndef IMAP_STORAGE
06043 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
06044 #else
06045 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06046 #endif
06047
06048 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
06049 ast_filerename(tmptxtfile, fn, NULL);
06050 rename(tmptxtfile, txtfile);
06051 inprocess_count(vmu->mailbox, vmu->context, -1);
06052
06053
06054
06055 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
06056 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
06057
06058 ast_unlock_path(dir);
06059 if (ast_check_realtime("voicemail_data")) {
06060 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
06061 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
06062 }
06063
06064
06065
06066 if (ast_fileexists(fn, NULL, NULL) > 0) {
06067 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
06068 }
06069
06070
06071 while (tmpptr) {
06072 struct ast_vm_user recipu, *recip;
06073 char *exten, *cntx;
06074
06075 exten = strsep(&tmpptr, "&");
06076 cntx = strchr(exten, '@');
06077 if (cntx) {
06078 *cntx = '\0';
06079 cntx++;
06080 }
06081 if ((recip = find_user(&recipu, cntx, exten))) {
06082 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
06083 free_user(recip);
06084 }
06085 }
06086 #ifndef IMAP_STORAGE
06087 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06088
06089 char sfn[PATH_MAX];
06090 char dfn[PATH_MAX];
06091 int x;
06092
06093 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
06094 x = last_message_index(vmu, urgdir) + 1;
06095 make_file(sfn, sizeof(sfn), dir, msgnum);
06096 make_file(dfn, sizeof(dfn), urgdir, x);
06097 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
06098 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
06099
06100 ast_copy_string(fn, dfn, sizeof(fn));
06101 msgnum = x;
06102 }
06103 #endif
06104
06105 if (ast_fileexists(fn, NULL, NULL)) {
06106 #ifdef IMAP_STORAGE
06107 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
06108 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06109 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06110 flag);
06111 #else
06112 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
06113 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06114 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06115 flag);
06116 #endif
06117 }
06118
06119
06120 if (ast_fileexists(fn, NULL, NULL)) {
06121 DISPOSE(dir, msgnum);
06122 }
06123 }
06124 }
06125 } else {
06126 inprocess_count(vmu->mailbox, vmu->context, -1);
06127 }
06128 if (res == '0') {
06129 goto transfer;
06130 } else if (res > 0 && res != 't')
06131 res = 0;
06132
06133 if (sound_duration < vmu->minsecs)
06134
06135 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06136 else
06137 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06138 } else
06139 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06140 leave_vm_out:
06141 free_user(vmu);
06142
06143 #ifdef IMAP_STORAGE
06144
06145 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06146 if (expungeonhangup == 1) {
06147 ast_mutex_lock(&vms->lock);
06148 #ifdef HAVE_IMAP_TK2006
06149 if (LEVELUIDPLUS (vms->mailstream)) {
06150 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06151 } else
06152 #endif
06153 mail_expunge(vms->mailstream);
06154 ast_mutex_unlock(&vms->lock);
06155 }
06156 #endif
06157
06158 ast_free(tmp);
06159 return res;
06160 }
06161
06162 #if !defined(IMAP_STORAGE)
06163 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06164 {
06165
06166
06167 int x, dest;
06168 char sfn[PATH_MAX];
06169 char dfn[PATH_MAX];
06170
06171 if (vm_lock_path(dir)) {
06172 return ERROR_LOCK_PATH;
06173 }
06174
06175 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06176 make_file(sfn, sizeof(sfn), dir, x);
06177 if (EXISTS(dir, x, sfn, NULL)) {
06178
06179 if (x != dest) {
06180 make_file(dfn, sizeof(dfn), dir, dest);
06181 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06182 }
06183
06184 dest++;
06185 }
06186 }
06187 ast_unlock_path(dir);
06188
06189 return dest;
06190 }
06191 #endif
06192
06193 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06194 {
06195 int d;
06196 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06197 return d;
06198 }
06199
06200 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06201 {
06202 #ifdef IMAP_STORAGE
06203
06204
06205 char sequence[10];
06206 char mailbox[256];
06207 int res;
06208
06209
06210 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06211
06212 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06213 ast_mutex_lock(&vms->lock);
06214
06215 if (box == OLD_FOLDER) {
06216 mail_setflag(vms->mailstream, sequence, "\\Seen");
06217 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06218 } else if (box == NEW_FOLDER) {
06219 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06220 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06221 }
06222 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06223 ast_mutex_unlock(&vms->lock);
06224 return 0;
06225 }
06226
06227 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06228 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06229 if (mail_create(vms->mailstream, mailbox) == NIL)
06230 ast_debug(5, "Folder exists.\n");
06231 else
06232 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06233 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06234 ast_mutex_unlock(&vms->lock);
06235 return res;
06236 #else
06237 char *dir = vms->curdir;
06238 char *username = vms->username;
06239 char *context = vmu->context;
06240 char sfn[PATH_MAX];
06241 char dfn[PATH_MAX];
06242 char ddir[PATH_MAX];
06243 const char *dbox = mbox(vmu, box);
06244 int x, i;
06245 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06246
06247 if (vm_lock_path(ddir))
06248 return ERROR_LOCK_PATH;
06249
06250 x = last_message_index(vmu, ddir) + 1;
06251
06252 if (box == 10 && x >= vmu->maxdeletedmsg) {
06253 x--;
06254 for (i = 1; i <= x; i++) {
06255
06256 make_file(sfn, sizeof(sfn), ddir, i);
06257 make_file(dfn, sizeof(dfn), ddir, i - 1);
06258 if (EXISTS(ddir, i, sfn, NULL)) {
06259 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06260 } else
06261 break;
06262 }
06263 } else {
06264 if (x >= vmu->maxmsg) {
06265 ast_unlock_path(ddir);
06266 return -1;
06267 }
06268 }
06269 make_file(sfn, sizeof(sfn), dir, msg);
06270 make_file(dfn, sizeof(dfn), ddir, x);
06271 if (strcmp(sfn, dfn)) {
06272 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06273 }
06274 ast_unlock_path(ddir);
06275 #endif
06276 return 0;
06277 }
06278
06279 static int adsi_logo(unsigned char *buf)
06280 {
06281 int bytes = 0;
06282 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06283 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06284 return bytes;
06285 }
06286
06287 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06288 {
06289 unsigned char buf[256];
06290 int bytes = 0;
06291 int x;
06292 char num[5];
06293
06294 *useadsi = 0;
06295 bytes += ast_adsi_data_mode(buf + bytes);
06296 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06297
06298 bytes = 0;
06299 bytes += adsi_logo(buf);
06300 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06301 #ifdef DISPLAY
06302 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06303 #endif
06304 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06305 bytes += ast_adsi_data_mode(buf + bytes);
06306 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06307
06308 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06309 bytes = 0;
06310 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06311 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06312 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06313 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06314 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06315 return 0;
06316 }
06317
06318 #ifdef DISPLAY
06319
06320 bytes = 0;
06321 bytes += ast_adsi_logo(buf);
06322 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06323 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06324 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06325 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06326 #endif
06327 bytes = 0;
06328 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06329 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06330 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06331 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06332 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06333 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06334 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06335
06336 #ifdef DISPLAY
06337
06338 bytes = 0;
06339 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06340 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06341
06342 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06343 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06344 #endif
06345
06346 bytes = 0;
06347
06348 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06349 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06350 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06351 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06352 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06353 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
06354 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06355
06356 #ifdef DISPLAY
06357
06358 bytes = 0;
06359 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
06360 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06361 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06362 #endif
06363
06364 bytes = 0;
06365 for (x = 0; x < 5; x++) {
06366 snprintf(num, sizeof(num), "%d", x);
06367 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06368 }
06369 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06370 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06371
06372 #ifdef DISPLAY
06373
06374 bytes = 0;
06375 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06376 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06377 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06378 #endif
06379
06380 if (ast_adsi_end_download(chan)) {
06381 bytes = 0;
06382 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06383 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06384 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06385 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06386 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06387 return 0;
06388 }
06389 bytes = 0;
06390 bytes += ast_adsi_download_disconnect(buf + bytes);
06391 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06392 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06393
06394 ast_debug(1, "Done downloading scripts...\n");
06395
06396 #ifdef DISPLAY
06397
06398 bytes = 0;
06399 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06400 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06401 #endif
06402 ast_debug(1, "Restarting session...\n");
06403
06404 bytes = 0;
06405
06406 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06407 *useadsi = 1;
06408 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06409 } else
06410 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06411
06412 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06413 return 0;
06414 }
06415
06416 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06417 {
06418 int x;
06419 if (!ast_adsi_available(chan))
06420 return;
06421 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06422 if (x < 0)
06423 return;
06424 if (!x) {
06425 if (adsi_load_vmail(chan, useadsi)) {
06426 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06427 return;
06428 }
06429 } else
06430 *useadsi = 1;
06431 }
06432
06433 static void adsi_login(struct ast_channel *chan)
06434 {
06435 unsigned char buf[256];
06436 int bytes = 0;
06437 unsigned char keys[8];
06438 int x;
06439 if (!ast_adsi_available(chan))
06440 return;
06441
06442 for (x = 0; x < 8; x++)
06443 keys[x] = 0;
06444
06445 keys[3] = ADSI_KEY_APPS + 3;
06446
06447 bytes += adsi_logo(buf + bytes);
06448 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06449 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06450 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06451 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06452 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06453 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06454 bytes += ast_adsi_set_keys(buf + bytes, keys);
06455 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06456 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06457 }
06458
06459 static void adsi_password(struct ast_channel *chan)
06460 {
06461 unsigned char buf[256];
06462 int bytes = 0;
06463 unsigned char keys[8];
06464 int x;
06465 if (!ast_adsi_available(chan))
06466 return;
06467
06468 for (x = 0; x < 8; x++)
06469 keys[x] = 0;
06470
06471 keys[3] = ADSI_KEY_APPS + 3;
06472
06473 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06474 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06475 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06476 bytes += ast_adsi_set_keys(buf + bytes, keys);
06477 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06478 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06479 }
06480
06481 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06482 {
06483 unsigned char buf[256];
06484 int bytes = 0;
06485 unsigned char keys[8];
06486 int x, y;
06487
06488 if (!ast_adsi_available(chan))
06489 return;
06490
06491 for (x = 0; x < 5; x++) {
06492 y = ADSI_KEY_APPS + 12 + start + x;
06493 if (y > ADSI_KEY_APPS + 12 + 4)
06494 y = 0;
06495 keys[x] = ADSI_KEY_SKT | y;
06496 }
06497 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06498 keys[6] = 0;
06499 keys[7] = 0;
06500
06501 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06502 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06503 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06504 bytes += ast_adsi_set_keys(buf + bytes, keys);
06505 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06506
06507 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06508 }
06509
06510 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06511 {
06512 int bytes = 0;
06513 unsigned char buf[256];
06514 char buf1[256], buf2[256];
06515 char fn2[PATH_MAX];
06516
06517 char cid[256] = "";
06518 char *val;
06519 char *name, *num;
06520 char datetime[21] = "";
06521 FILE *f;
06522
06523 unsigned char keys[8];
06524
06525 int x;
06526
06527 if (!ast_adsi_available(chan))
06528 return;
06529
06530
06531 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06532 f = fopen(fn2, "r");
06533 if (f) {
06534 while (!feof(f)) {
06535 if (!fgets((char *) buf, sizeof(buf), f)) {
06536 continue;
06537 }
06538 if (!feof(f)) {
06539 char *stringp = NULL;
06540 stringp = (char *) buf;
06541 strsep(&stringp, "=");
06542 val = strsep(&stringp, "=");
06543 if (!ast_strlen_zero(val)) {
06544 if (!strcmp((char *) buf, "callerid"))
06545 ast_copy_string(cid, val, sizeof(cid));
06546 if (!strcmp((char *) buf, "origdate"))
06547 ast_copy_string(datetime, val, sizeof(datetime));
06548 }
06549 }
06550 }
06551 fclose(f);
06552 }
06553
06554 for (x = 0; x < 5; x++)
06555 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06556 keys[6] = 0x0;
06557 keys[7] = 0x0;
06558
06559 if (!vms->curmsg) {
06560
06561 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06562 }
06563 if (vms->curmsg >= vms->lastmsg) {
06564
06565 if (vms->curmsg) {
06566
06567 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06568 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06569
06570 } else {
06571
06572 keys[3] = 1;
06573 }
06574 }
06575
06576 if (!ast_strlen_zero(cid)) {
06577 ast_callerid_parse(cid, &name, &num);
06578 if (!name)
06579 name = num;
06580 } else
06581 name = "Unknown Caller";
06582
06583
06584 #ifdef IMAP_STORAGE
06585 ast_mutex_lock(&vms->lock);
06586 #endif
06587 if (vms->deleted[vms->curmsg]) {
06588 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06589 }
06590 #ifdef IMAP_STORAGE
06591 ast_mutex_unlock(&vms->lock);
06592 #endif
06593
06594
06595 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06596 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06597 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06598 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06599
06600 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06601 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06602 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06603 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06604 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06605 bytes += ast_adsi_set_keys(buf + bytes, keys);
06606 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06607
06608 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06609 }
06610
06611 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06612 {
06613 int bytes = 0;
06614 unsigned char buf[256];
06615 unsigned char keys[8];
06616
06617 int x;
06618
06619 if (!ast_adsi_available(chan))
06620 return;
06621
06622
06623 for (x = 0; x < 5; x++)
06624 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06625
06626 keys[6] = 0x0;
06627 keys[7] = 0x0;
06628
06629 if (!vms->curmsg) {
06630
06631 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06632 }
06633 if (vms->curmsg >= vms->lastmsg) {
06634
06635 if (vms->curmsg) {
06636
06637 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06638 } else {
06639
06640 keys[3] = 1;
06641 }
06642 }
06643
06644
06645 #ifdef IMAP_STORAGE
06646 ast_mutex_lock(&vms->lock);
06647 #endif
06648 if (vms->deleted[vms->curmsg]) {
06649 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06650 }
06651 #ifdef IMAP_STORAGE
06652 ast_mutex_unlock(&vms->lock);
06653 #endif
06654
06655
06656 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06657 bytes += ast_adsi_set_keys(buf + bytes, keys);
06658 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06659
06660 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06661 }
06662
06663 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06664 {
06665 unsigned char buf[256] = "";
06666 char buf1[256] = "", buf2[256] = "";
06667 int bytes = 0;
06668 unsigned char keys[8];
06669 int x;
06670
06671 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06672 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06673 if (!ast_adsi_available(chan))
06674 return;
06675 if (vms->newmessages) {
06676 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06677 if (vms->oldmessages) {
06678 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06679 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06680 } else {
06681 snprintf(buf2, sizeof(buf2), "%s.", newm);
06682 }
06683 } else if (vms->oldmessages) {
06684 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06685 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06686 } else {
06687 strcpy(buf1, "You have no messages.");
06688 buf2[0] = ' ';
06689 buf2[1] = '\0';
06690 }
06691 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06692 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06693 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06694
06695 for (x = 0; x < 6; x++)
06696 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06697 keys[6] = 0;
06698 keys[7] = 0;
06699
06700
06701 if (vms->lastmsg < 0)
06702 keys[0] = 1;
06703 bytes += ast_adsi_set_keys(buf + bytes, keys);
06704
06705 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06706
06707 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06708 }
06709
06710 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06711 {
06712 unsigned char buf[256] = "";
06713 char buf1[256] = "", buf2[256] = "";
06714 int bytes = 0;
06715 unsigned char keys[8];
06716 int x;
06717
06718 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06719
06720 if (!ast_adsi_available(chan))
06721 return;
06722
06723
06724 for (x = 0; x < 6; x++)
06725 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06726
06727 keys[6] = 0;
06728 keys[7] = 0;
06729
06730 if ((vms->lastmsg + 1) < 1)
06731 keys[0] = 0;
06732
06733 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06734 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06735
06736 if (vms->lastmsg + 1)
06737 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06738 else
06739 strcpy(buf2, "no messages.");
06740 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06741 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06742 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06743 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06744 bytes += ast_adsi_set_keys(buf + bytes, keys);
06745
06746 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06747
06748 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06749
06750 }
06751
06752
06753
06754
06755
06756
06757
06758
06759
06760
06761
06762
06763
06764
06765
06766 static void adsi_goodbye(struct ast_channel *chan)
06767 {
06768 unsigned char buf[256];
06769 int bytes = 0;
06770
06771 if (!ast_adsi_available(chan))
06772 return;
06773 bytes += adsi_logo(buf + bytes);
06774 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06775 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06776 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06777 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06778
06779 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06780 }
06781
06782
06783
06784
06785
06786 static int get_folder(struct ast_channel *chan, int start)
06787 {
06788 int x;
06789 int d;
06790 char fn[PATH_MAX];
06791 d = ast_play_and_wait(chan, "vm-press");
06792 if (d)
06793 return d;
06794 for (x = start; x < 5; x++) {
06795 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06796 return d;
06797 d = ast_play_and_wait(chan, "vm-for");
06798 if (d)
06799 return d;
06800 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06801
06802
06803
06804
06805 if (x == 0) {
06806 if (ast_fileexists(fn, NULL, NULL)) {
06807 d = vm_play_folder_name(chan, fn);
06808 } else {
06809 ast_verb(1, "failed to find %s\n", fn);
06810 d = vm_play_folder_name(chan, "vm-INBOX");
06811 }
06812 } else {
06813 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
06814 d = vm_play_folder_name(chan, fn);
06815 }
06816
06817 if (d)
06818 return d;
06819 d = ast_waitfordigit(chan, 500);
06820 if (d)
06821 return d;
06822 }
06823
06824 d = ast_play_and_wait(chan, "vm-tocancel");
06825 if (d)
06826 return d;
06827 d = ast_waitfordigit(chan, 4000);
06828 return d;
06829 }
06830
06831
06832
06833
06834
06835
06836
06837
06838
06839
06840
06841
06842
06843 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06844 {
06845 int res = 0;
06846 int loops = 0;
06847
06848 res = ast_play_and_wait(chan, fn);
06849 while (((res < '0') || (res > '9')) &&
06850 (res != '#') && (res >= 0) &&
06851 loops < 4) {
06852 res = get_folder(chan, 0);
06853 loops++;
06854 }
06855 if (loops == 4) {
06856 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
06857 return '#';
06858 }
06859 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
06860 return res;
06861 }
06862
06863
06864
06865
06866
06867
06868
06869
06870
06871
06872
06873
06874
06875
06876
06877
06878
06879
06880
06881 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06882 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06883 {
06884 int cmd = 0;
06885 int retries = 0, prepend_duration = 0, already_recorded = 0;
06886 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06887 char textfile[PATH_MAX];
06888 struct ast_config *msg_cfg;
06889 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06890 #ifndef IMAP_STORAGE
06891 signed char zero_gain = 0;
06892 #endif
06893 const char *duration_str;
06894
06895
06896 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06897 strcpy(textfile, msgfile);
06898 strcpy(backup, msgfile);
06899 strcpy(backup_textfile, msgfile);
06900 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06901 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06902 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06903
06904 if ((msg_cfg = ast_config_load(textfile, config_flags)) && msg_cfg != CONFIG_STATUS_FILEINVALID && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06905 *duration = atoi(duration_str);
06906 } else {
06907 *duration = 0;
06908 }
06909
06910 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06911 if (cmd)
06912 retries = 0;
06913 switch (cmd) {
06914 case '1':
06915
06916 #ifdef IMAP_STORAGE
06917
06918 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06919 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06920 ast_play_and_wait(chan, INTRO);
06921 ast_play_and_wait(chan, "beep");
06922 cmd = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag);
06923 if (cmd == -1) {
06924 break;
06925 }
06926 cmd = 't';
06927 #else
06928
06929
06930
06931 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06932 strcpy(textfile, msgfile);
06933 strncat(textfile, ".txt", sizeof(textfile) - 1);
06934 *duration = 0;
06935
06936
06937 if (!msg_cfg) {
06938 cmd = 0;
06939 break;
06940 }
06941
06942
06943 #ifndef IMAP_STORAGE
06944 if (already_recorded) {
06945 ast_filecopy(backup, msgfile, NULL);
06946 copy(backup_textfile, textfile);
06947 }
06948 else {
06949 ast_filecopy(msgfile, backup, NULL);
06950 copy(textfile, backup_textfile);
06951 }
06952 #endif
06953 already_recorded = 1;
06954
06955 if (record_gain)
06956 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06957
06958 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
06959
06960 if (cmd == 'S') {
06961 ast_stream_and_wait(chan, vm_pls_try_again, "");
06962 ast_stream_and_wait(chan, vm_prepend_timeout, "");
06963 ast_filerename(backup, msgfile, NULL);
06964 }
06965
06966 if (record_gain)
06967 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06968
06969
06970 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06971 *duration = atoi(duration_str);
06972
06973 if (prepend_duration) {
06974 struct ast_category *msg_cat;
06975
06976 char duration_buf[12];
06977
06978 *duration += prepend_duration;
06979 msg_cat = ast_category_get(msg_cfg, "message");
06980 snprintf(duration_buf, 11, "%ld", *duration);
06981 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06982 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
06983 }
06984 }
06985
06986 #endif
06987 break;
06988 case '2':
06989
06990 #ifdef IMAP_STORAGE
06991 *vms->introfn = '\0';
06992 #endif
06993 cmd = 't';
06994 break;
06995 case '*':
06996 cmd = '*';
06997 break;
06998 default:
06999
07000 already_recorded = 0;
07001
07002 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
07003
07004 if (!cmd) {
07005 cmd = ast_play_and_wait(chan, "vm-starmain");
07006
07007 }
07008 if (!cmd) {
07009 cmd = ast_waitfordigit(chan, 6000);
07010 }
07011 if (!cmd) {
07012 retries++;
07013 }
07014 if (retries > 3) {
07015 cmd = '*';
07016 }
07017 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07018 }
07019 }
07020
07021 if (msg_cfg)
07022 ast_config_destroy(msg_cfg);
07023 if (prepend_duration)
07024 *duration = prepend_duration;
07025
07026 if (already_recorded && cmd == -1) {
07027
07028 ast_filerename(backup, msgfile, NULL);
07029 rename(backup_textfile, textfile);
07030 }
07031
07032 if (cmd == 't' || cmd == 'S')
07033 cmd = 0;
07034 return cmd;
07035 }
07036
07037 static void queue_mwi_event(const char *box, int urgent, int new, int old)
07038 {
07039 struct ast_event *event;
07040 char *mailbox, *context;
07041
07042
07043 context = mailbox = ast_strdupa(box);
07044 strsep(&context, "@");
07045 if (ast_strlen_zero(context))
07046 context = "default";
07047
07048 if (!(event = ast_event_new(AST_EVENT_MWI,
07049 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
07050 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
07051 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
07052 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
07053 AST_EVENT_IE_END))) {
07054 return;
07055 }
07056
07057 ast_event_queue_and_cache(event);
07058 }
07059
07060
07061
07062
07063
07064
07065
07066
07067
07068
07069
07070
07071
07072
07073
07074 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)
07075 {
07076 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
07077 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
07078 const char *category;
07079 char *myserveremail = serveremail;
07080
07081 ast_channel_lock(chan);
07082 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
07083 category = ast_strdupa(category);
07084 }
07085 ast_channel_unlock(chan);
07086
07087 #ifndef IMAP_STORAGE
07088 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
07089 #else
07090 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
07091 #endif
07092 make_file(fn, sizeof(fn), todir, msgnum);
07093 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
07094
07095 if (!ast_strlen_zero(vmu->attachfmt)) {
07096 if (strstr(fmt, vmu->attachfmt))
07097 fmt = vmu->attachfmt;
07098 else
07099 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);
07100 }
07101
07102
07103 fmt = ast_strdupa(fmt);
07104 stringp = fmt;
07105 strsep(&stringp, "|");
07106
07107 if (!ast_strlen_zero(vmu->serveremail))
07108 myserveremail = vmu->serveremail;
07109
07110 if (!ast_strlen_zero(vmu->email)) {
07111 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
07112
07113 if (attach_user_voicemail)
07114 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
07115
07116
07117 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
07118
07119 if (attach_user_voicemail)
07120 DISPOSE(todir, msgnum);
07121 }
07122
07123 if (!ast_strlen_zero(vmu->pager)) {
07124 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
07125 }
07126
07127 if (ast_test_flag(vmu, VM_DELETE))
07128 DELETE(todir, msgnum, fn, vmu);
07129
07130
07131 if (ast_app_has_voicemail(ext_context, NULL))
07132 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
07133
07134 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
07135
07136 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);
07137 run_externnotify(vmu->context, vmu->mailbox, flag);
07138
07139 #ifdef IMAP_STORAGE
07140 vm_delete(fn);
07141 if (ast_test_flag(vmu, VM_DELETE)) {
07142 vm_imap_delete(NULL, vms->curmsg, vmu);
07143 vms->newmessages--;
07144 }
07145 #endif
07146
07147 return 0;
07148 }
07149
07150
07151
07152
07153
07154
07155
07156
07157
07158
07159
07160
07161
07162
07163
07164
07165
07166
07167
07168
07169
07170
07171
07172
07173
07174
07175
07176
07177 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)
07178 {
07179 #ifdef IMAP_STORAGE
07180 int todircount = 0;
07181 struct vm_state *dstvms;
07182 #endif
07183 char username[70]="";
07184 char fn[PATH_MAX];
07185 char ecodes[16] = "#";
07186 int res = 0, cmd = 0;
07187 struct ast_vm_user *receiver = NULL, *vmtmp;
07188 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
07189 char *stringp;
07190 const char *s;
07191 int saved_messages = 0;
07192 int valid_extensions = 0;
07193 char *dir;
07194 int curmsg;
07195 char urgent_str[7] = "";
07196 int prompt_played = 0;
07197 #ifndef IMAP_STORAGE
07198 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07199 #endif
07200 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07201 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07202 }
07203
07204 if (vms == NULL) return -1;
07205 dir = vms->curdir;
07206 curmsg = vms->curmsg;
07207
07208 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
07209 while (!res && !valid_extensions) {
07210 int use_directory = 0;
07211 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07212 int done = 0;
07213 int retries = 0;
07214 cmd = 0;
07215 while ((cmd >= 0) && !done ){
07216 if (cmd)
07217 retries = 0;
07218 switch (cmd) {
07219 case '1':
07220 use_directory = 0;
07221 done = 1;
07222 break;
07223 case '2':
07224 use_directory = 1;
07225 done = 1;
07226 break;
07227 case '*':
07228 cmd = 't';
07229 done = 1;
07230 break;
07231 default:
07232
07233 cmd = ast_play_and_wait(chan, "vm-forward");
07234 if (!cmd) {
07235 cmd = ast_waitfordigit(chan, 3000);
07236 }
07237 if (!cmd) {
07238 retries++;
07239 }
07240 if (retries > 3) {
07241 cmd = 't';
07242 done = 1;
07243 }
07244 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07245 }
07246 }
07247 if (cmd < 0 || cmd == 't')
07248 break;
07249 }
07250
07251 if (use_directory) {
07252
07253
07254 char old_context[sizeof(chan->context)];
07255 char old_exten[sizeof(chan->exten)];
07256 int old_priority;
07257 struct ast_app* directory_app;
07258
07259 directory_app = pbx_findapp("Directory");
07260 if (directory_app) {
07261 char vmcontext[256];
07262
07263 memcpy(old_context, chan->context, sizeof(chan->context));
07264 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07265 old_priority = chan->priority;
07266
07267
07268 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07269 res = pbx_exec(chan, directory_app, vmcontext);
07270
07271 ast_copy_string(username, chan->exten, sizeof(username));
07272
07273
07274 memcpy(chan->context, old_context, sizeof(chan->context));
07275 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07276 chan->priority = old_priority;
07277 } else {
07278 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07279 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07280 }
07281 } else {
07282
07283 ast_test_suite_event_notify("PLAYBACK", "Message: vm-extension");
07284 res = ast_streamfile(chan, "vm-extension", chan->language);
07285 prompt_played++;
07286 if (res || prompt_played > 4)
07287 break;
07288 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07289 break;
07290 }
07291
07292
07293 if (ast_strlen_zero(username))
07294 continue;
07295 stringp = username;
07296 s = strsep(&stringp, "*");
07297
07298 valid_extensions = 1;
07299 while (s) {
07300 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07301 int oldmsgs;
07302 int newmsgs;
07303 int capacity;
07304 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07305 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07306
07307 res = ast_play_and_wait(chan, "pbx-invalid");
07308 valid_extensions = 0;
07309 break;
07310 }
07311 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07312 if ((newmsgs + oldmsgs) >= capacity) {
07313 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07314 res = ast_play_and_wait(chan, "vm-mailboxfull");
07315 valid_extensions = 0;
07316 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07317 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07318 free_user(vmtmp);
07319 }
07320 inprocess_count(receiver->mailbox, receiver->context, -1);
07321 break;
07322 }
07323 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07324 } else {
07325
07326
07327
07328
07329
07330 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07331 free_user(receiver);
07332 }
07333 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07334
07335 res = ast_play_and_wait(chan, "pbx-invalid");
07336 valid_extensions = 0;
07337 break;
07338 }
07339
07340
07341 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07342 RETRIEVE(fn, -1, s, receiver->context);
07343 if (ast_fileexists(fn, NULL, NULL) > 0) {
07344 res = ast_stream_and_wait(chan, fn, ecodes);
07345 if (res) {
07346 DISPOSE(fn, -1);
07347 return res;
07348 }
07349 } else {
07350 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07351 }
07352 DISPOSE(fn, -1);
07353
07354 s = strsep(&stringp, "*");
07355 }
07356
07357 if (valid_extensions)
07358 break;
07359 }
07360
07361 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07362 return res;
07363 if (is_new_message == 1) {
07364 struct leave_vm_options leave_options;
07365 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07366 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07367
07368
07369 memset(&leave_options, 0, sizeof(leave_options));
07370 leave_options.record_gain = record_gain;
07371 cmd = leave_voicemail(chan, mailbox, &leave_options);
07372 } else {
07373
07374 long duration = 0;
07375 struct vm_state vmstmp;
07376 int copy_msg_result = 0;
07377 memcpy(&vmstmp, vms, sizeof(vmstmp));
07378
07379 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07380
07381 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07382 if (!cmd) {
07383 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07384 #ifdef IMAP_STORAGE
07385 int attach_user_voicemail;
07386 char *myserveremail = serveremail;
07387
07388
07389 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07390 if (!dstvms) {
07391 dstvms = create_vm_state_from_user(vmtmp);
07392 }
07393 if (dstvms) {
07394 init_mailstream(dstvms, 0);
07395 if (!dstvms->mailstream) {
07396 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07397 } else {
07398 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07399 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07400 }
07401 } else {
07402 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07403 }
07404 if (!ast_strlen_zero(vmtmp->serveremail))
07405 myserveremail = vmtmp->serveremail;
07406 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07407
07408 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07409 dstvms->curbox,
07410 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07411 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07412 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07413 NULL, urgent_str);
07414 #else
07415 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07416 #endif
07417 saved_messages++;
07418 AST_LIST_REMOVE_CURRENT(list);
07419 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07420 free_user(vmtmp);
07421 if (res)
07422 break;
07423 }
07424 AST_LIST_TRAVERSE_SAFE_END;
07425 if (saved_messages > 0 && !copy_msg_result) {
07426
07427
07428
07429
07430
07431
07432
07433
07434 #ifdef IMAP_STORAGE
07435
07436 if (ast_strlen_zero(vmstmp.introfn))
07437 #endif
07438 res = ast_play_and_wait(chan, "vm-msgsaved");
07439 }
07440 #ifndef IMAP_STORAGE
07441 else {
07442
07443 res = ast_play_and_wait(chan, "vm-mailboxfull");
07444 }
07445
07446 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07447 strcpy(textfile, msgfile);
07448 strcpy(backup, msgfile);
07449 strcpy(backup_textfile, msgfile);
07450 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07451 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07452 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07453 if (ast_fileexists(backup, NULL, NULL) > 0) {
07454 ast_filerename(backup, msgfile, NULL);
07455 rename(backup_textfile, textfile);
07456 }
07457 #endif
07458 }
07459 DISPOSE(dir, curmsg);
07460 #ifndef IMAP_STORAGE
07461 if (cmd) {
07462 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07463 strcpy(textfile, msgfile);
07464 strcpy(backup_textfile, msgfile);
07465 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07466 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07467 rename(backup_textfile, textfile);
07468 }
07469 #endif
07470 }
07471
07472
07473 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07474 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07475 free_user(vmtmp);
07476 }
07477 return res ? res : cmd;
07478 }
07479
07480 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07481 {
07482 int res;
07483 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07484 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07485 return res;
07486 }
07487
07488 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07489 {
07490 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
07491 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);
07492 }
07493
07494 static int play_message_category(struct ast_channel *chan, const char *category)
07495 {
07496 int res = 0;
07497
07498 if (!ast_strlen_zero(category))
07499 res = ast_play_and_wait(chan, category);
07500
07501 if (res) {
07502 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07503 res = 0;
07504 }
07505
07506 return res;
07507 }
07508
07509 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07510 {
07511 int res = 0;
07512 struct vm_zone *the_zone = NULL;
07513 time_t t;
07514
07515 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07516 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07517 return 0;
07518 }
07519
07520
07521 if (!ast_strlen_zero(vmu->zonetag)) {
07522
07523 struct vm_zone *z;
07524 AST_LIST_LOCK(&zones);
07525 AST_LIST_TRAVERSE(&zones, z, list) {
07526 if (!strcmp(z->name, vmu->zonetag)) {
07527 the_zone = z;
07528 break;
07529 }
07530 }
07531 AST_LIST_UNLOCK(&zones);
07532 }
07533
07534
07535 #if 0
07536
07537 ast_localtime(&t, &time_now, NULL);
07538 tv_now = ast_tvnow();
07539 ast_localtime(&tv_now, &time_then, NULL);
07540
07541
07542 if (time_now.tm_year == time_then.tm_year)
07543 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07544 else
07545 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07546 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07547
07548
07549 #endif
07550 if (the_zone) {
07551 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07552 } else if (!strncasecmp(chan->language, "de", 2)) {
07553 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07554 } else if (!strncasecmp(chan->language, "gr", 2)) {
07555 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07556 } else if (!strncasecmp(chan->language, "it", 2)) {
07557 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);
07558 } else if (!strncasecmp(chan->language, "nl", 2)) {
07559 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07560 } else if (!strncasecmp(chan->language, "no", 2)) {
07561 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07562 } else if (!strncasecmp(chan->language, "pl", 2)) {
07563 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07564 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07565 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);
07566 } else if (!strncasecmp(chan->language, "se", 2)) {
07567 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07568 } else if (!strncasecmp(chan->language, "zh", 2)) {
07569 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07570 } else if (!strncasecmp(chan->language, "vi", 2)) {
07571 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);
07572 } else {
07573 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07574 }
07575 #if 0
07576 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07577 #endif
07578 return res;
07579 }
07580
07581
07582
07583 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07584 {
07585 int res = 0;
07586 int i;
07587 char *callerid, *name;
07588 char prefile[PATH_MAX] = "";
07589
07590
07591
07592
07593
07594
07595
07596
07597
07598 if ((cid == NULL)||(context == NULL))
07599 return res;
07600
07601
07602 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07603 ast_callerid_parse(cid, &name, &callerid);
07604 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07605
07606
07607 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07608 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07609 if ((strcmp(cidinternalcontexts[i], context) == 0))
07610 break;
07611 }
07612 if (i != MAX_NUM_CID_CONTEXTS){
07613 if (!res) {
07614 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07615 if (!ast_strlen_zero(prefile)) {
07616
07617 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07618 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07619 if (!callback)
07620 res = wait_file2(chan, vms, "vm-from");
07621 res = ast_stream_and_wait(chan, prefile, "");
07622 } else {
07623 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07624
07625 if (!callback)
07626 res = wait_file2(chan, vms, "vm-from-extension");
07627 res = ast_say_digit_str(chan, callerid, "", chan->language);
07628 }
07629 }
07630 }
07631 } else if (!res) {
07632 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07633
07634 if (!callback)
07635 res = wait_file2(chan, vms, "vm-from-phonenumber");
07636 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07637 }
07638 } else {
07639
07640 ast_debug(1, "VM-CID: From an unknown number\n");
07641
07642 res = wait_file2(chan, vms, "vm-unknown-caller");
07643 }
07644 return res;
07645 }
07646
07647 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07648 {
07649 int res = 0;
07650 int durationm;
07651 int durations;
07652
07653 if (duration == NULL)
07654 return res;
07655
07656
07657 durations = atoi(duration);
07658 durationm = (durations / 60);
07659
07660 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07661
07662 if ((!res) && (durationm >= minduration)) {
07663 res = wait_file2(chan, vms, "vm-duration");
07664
07665
07666 if (!strncasecmp(chan->language, "pl", 2)) {
07667 div_t num = div(durationm, 10);
07668
07669 if (durationm == 1) {
07670 res = ast_play_and_wait(chan, "digits/1z");
07671 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07672 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07673 if (num.rem == 2) {
07674 if (!num.quot) {
07675 res = ast_play_and_wait(chan, "digits/2-ie");
07676 } else {
07677 res = say_and_wait(chan, durationm - 2 , chan->language);
07678 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07679 }
07680 } else {
07681 res = say_and_wait(chan, durationm, chan->language);
07682 }
07683 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07684 } else {
07685 res = say_and_wait(chan, durationm, chan->language);
07686 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07687 }
07688
07689 } else {
07690 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07691 res = wait_file2(chan, vms, "vm-minutes");
07692 }
07693 }
07694 return res;
07695 }
07696
07697 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07698 {
07699 int res = 0;
07700 char filename[256], *cid;
07701 const char *origtime, *context, *category, *duration, *flag;
07702 struct ast_config *msg_cfg;
07703 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07704
07705 vms->starting = 0;
07706 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07707 adsi_message(chan, vms);
07708 if (!vms->curmsg) {
07709 res = wait_file2(chan, vms, "vm-first");
07710 } else if (vms->curmsg == vms->lastmsg) {
07711 res = wait_file2(chan, vms, "vm-last");
07712 }
07713
07714 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07715 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07716 msg_cfg = ast_config_load(filename, config_flags);
07717 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
07718 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07719 return 0;
07720 }
07721 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07722
07723
07724 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07725 res = wait_file2(chan, vms, "vm-Urgent");
07726 }
07727
07728 if (!res) {
07729
07730
07731 if (!strncasecmp(chan->language, "pl", 2)) {
07732 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07733 int ten, one;
07734 char nextmsg[256];
07735 ten = (vms->curmsg + 1) / 10;
07736 one = (vms->curmsg + 1) % 10;
07737
07738 if (vms->curmsg < 20) {
07739 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07740 res = wait_file2(chan, vms, nextmsg);
07741 } else {
07742 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07743 res = wait_file2(chan, vms, nextmsg);
07744 if (one > 0) {
07745 if (!res) {
07746 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07747 res = wait_file2(chan, vms, nextmsg);
07748 }
07749 }
07750 }
07751 }
07752 if (!res)
07753 res = wait_file2(chan, vms, "vm-message");
07754
07755 } else if (!strncasecmp(chan->language, "he", 2)) {
07756 if (!vms->curmsg) {
07757 res = wait_file2(chan, vms, "vm-message");
07758 res = wait_file2(chan, vms, "vm-first");
07759 } else if (vms->curmsg == vms->lastmsg) {
07760 res = wait_file2(chan, vms, "vm-message");
07761 res = wait_file2(chan, vms, "vm-last");
07762 } else {
07763 res = wait_file2(chan, vms, "vm-message");
07764 res = wait_file2(chan, vms, "vm-number");
07765 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07766 }
07767
07768 } else if (!strncasecmp(chan->language, "vi", 2)) {
07769 if (!vms->curmsg) {
07770 res = wait_file2(chan, vms, "vm-message");
07771 res = wait_file2(chan, vms, "vm-first");
07772 } else if (vms->curmsg == vms->lastmsg) {
07773 res = wait_file2(chan, vms, "vm-message");
07774 res = wait_file2(chan, vms, "vm-last");
07775 } else {
07776 res = wait_file2(chan, vms, "vm-message");
07777 res = wait_file2(chan, vms, "vm-number");
07778 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07779 }
07780 } else {
07781 if (!strncasecmp(chan->language, "se", 2)) {
07782 res = wait_file2(chan, vms, "vm-meddelandet");
07783 } else {
07784 res = wait_file2(chan, vms, "vm-message");
07785 }
07786 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07787 if (!res) {
07788 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
07789 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07790 }
07791 }
07792 }
07793 }
07794
07795 if (!msg_cfg) {
07796 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07797 return 0;
07798 }
07799
07800 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07801 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07802 DISPOSE(vms->curdir, vms->curmsg);
07803 ast_config_destroy(msg_cfg);
07804 return 0;
07805 }
07806
07807 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07808 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07809 category = ast_variable_retrieve(msg_cfg, "message", "category");
07810
07811 context = ast_variable_retrieve(msg_cfg, "message", "context");
07812 if (!strncasecmp("macro", context, 5))
07813 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07814 if (!res) {
07815 res = play_message_category(chan, category);
07816 }
07817 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
07818 res = play_message_datetime(chan, vmu, origtime, filename);
07819 }
07820 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
07821 res = play_message_callerid(chan, vms, cid, context, 0);
07822 }
07823 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
07824 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07825 }
07826
07827 if (res == '1') {
07828 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07829 res = 0;
07830 }
07831 ast_config_destroy(msg_cfg);
07832
07833 if (!res) {
07834 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07835 #ifdef IMAP_STORAGE
07836 ast_mutex_lock(&vms->lock);
07837 #endif
07838 vms->heard[vms->curmsg] = 1;
07839 #ifdef IMAP_STORAGE
07840 ast_mutex_unlock(&vms->lock);
07841
07842
07843
07844 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07845 wait_file(chan, vms, vms->introfn);
07846 }
07847 #endif
07848 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07849 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07850 res = 0;
07851 }
07852 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07853 }
07854 DISPOSE(vms->curdir, vms->curmsg);
07855 return res;
07856 }
07857
07858 #ifdef IMAP_STORAGE
07859 static int imap_remove_file(char *dir, int msgnum)
07860 {
07861 char fn[PATH_MAX];
07862 char full_fn[PATH_MAX];
07863 char intro[PATH_MAX] = {0,};
07864
07865 if (msgnum > -1) {
07866 make_file(fn, sizeof(fn), dir, msgnum);
07867 snprintf(intro, sizeof(intro), "%sintro", fn);
07868 } else
07869 ast_copy_string(fn, dir, sizeof(fn));
07870
07871 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07872 ast_filedelete(fn, NULL);
07873 if (!ast_strlen_zero(intro)) {
07874 ast_filedelete(intro, NULL);
07875 }
07876 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07877 unlink(full_fn);
07878 }
07879 return 0;
07880 }
07881
07882
07883
07884 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07885 {
07886 char *file, *filename;
07887 char *attachment;
07888 char arg[10];
07889 int i;
07890 BODY* body;
07891
07892 file = strrchr(ast_strdupa(dir), '/');
07893 if (file) {
07894 *file++ = '\0';
07895 } else {
07896 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07897 return -1;
07898 }
07899
07900 ast_mutex_lock(&vms->lock);
07901 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07902 mail_fetchstructure(vms->mailstream, i + 1, &body);
07903
07904 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07905 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07906 } else {
07907 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07908 ast_mutex_unlock(&vms->lock);
07909 return -1;
07910 }
07911 filename = strsep(&attachment, ".");
07912 if (!strcmp(filename, file)) {
07913 sprintf(arg, "%d", i + 1);
07914 mail_setflag(vms->mailstream, arg, "\\DELETED");
07915 }
07916 }
07917 mail_expunge(vms->mailstream);
07918 ast_mutex_unlock(&vms->lock);
07919 return 0;
07920 }
07921
07922 #elif !defined(IMAP_STORAGE)
07923 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07924 {
07925 int count_msg, last_msg;
07926
07927 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07928
07929
07930
07931
07932 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07933
07934
07935 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07936
07937
07938 count_msg = count_messages(vmu, vms->curdir);
07939 if (count_msg < 0) {
07940 return count_msg;
07941 } else {
07942 vms->lastmsg = count_msg - 1;
07943 }
07944
07945 if (vm_allocate_dh(vms, vmu, count_msg)) {
07946 return -1;
07947 }
07948
07949
07950
07951
07952
07953
07954
07955
07956 if (vm_lock_path(vms->curdir)) {
07957 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07958 return ERROR_LOCK_PATH;
07959 }
07960
07961
07962 last_msg = last_message_index(vmu, vms->curdir);
07963 ast_unlock_path(vms->curdir);
07964
07965 if (last_msg < -1) {
07966 return last_msg;
07967 } else if (vms->lastmsg != last_msg) {
07968 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);
07969 resequence_mailbox(vmu, vms->curdir, count_msg);
07970 }
07971
07972 return 0;
07973 }
07974 #endif
07975
07976 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
07977 {
07978 int x = 0;
07979 int last_msg_idx = 0;
07980
07981 #ifndef IMAP_STORAGE
07982 int res = 0, nummsg;
07983 char fn2[PATH_MAX];
07984 #endif
07985
07986 if (vms->lastmsg <= -1) {
07987 goto done;
07988 }
07989
07990 vms->curmsg = -1;
07991 #ifndef IMAP_STORAGE
07992
07993 if (vm_lock_path(vms->curdir)) {
07994 return ERROR_LOCK_PATH;
07995 }
07996
07997
07998 last_msg_idx = last_message_index(vmu, vms->curdir);
07999 if (last_msg_idx != vms->lastmsg) {
08000 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
08001 }
08002
08003
08004 for (x = 0; x < last_msg_idx + 1; x++) {
08005 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
08006
08007 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08008 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
08009 break;
08010 }
08011 vms->curmsg++;
08012 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
08013 if (strcmp(vms->fn, fn2)) {
08014 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
08015 }
08016 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
08017
08018 res = save_to_folder(vmu, vms, x, 1);
08019 if (res == ERROR_LOCK_PATH) {
08020
08021 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
08022 vms->deleted[x] = 0;
08023 vms->heard[x] = 0;
08024 --x;
08025 }
08026 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
08027
08028 res = save_to_folder(vmu, vms, x, 10);
08029 if (res == ERROR_LOCK_PATH) {
08030
08031 vms->deleted[x] = 0;
08032 vms->heard[x] = 0;
08033 --x;
08034 }
08035 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
08036
08037
08038 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08039 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08040 DELETE(vms->curdir, x, vms->fn, vmu);
08041 }
08042 }
08043 }
08044
08045
08046 nummsg = x - 1;
08047 for (x = vms->curmsg + 1; x <= nummsg; x++) {
08048 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08049 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08050 DELETE(vms->curdir, x, vms->fn, vmu);
08051 }
08052 }
08053 ast_unlock_path(vms->curdir);
08054 #else
08055 ast_mutex_lock(&vms->lock);
08056 if (vms->deleted) {
08057
08058
08059 last_msg_idx = vms->dh_arraysize;
08060 for (x = last_msg_idx - 1; x >= 0; x--) {
08061 if (vms->deleted[x]) {
08062 ast_debug(3, "IMAP delete of %d\n", x);
08063 DELETE(vms->curdir, x, vms->fn, vmu);
08064 }
08065 }
08066 }
08067 #endif
08068
08069 done:
08070 if (vms->deleted) {
08071 ast_free(vms->deleted);
08072 vms->deleted = NULL;
08073 }
08074 if (vms->heard) {
08075 ast_free(vms->heard);
08076 vms->heard = NULL;
08077 }
08078 vms->dh_arraysize = 0;
08079 #ifdef IMAP_STORAGE
08080 ast_mutex_unlock(&vms->lock);
08081 #endif
08082
08083 return 0;
08084 }
08085
08086
08087
08088
08089
08090
08091
08092 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08093 {
08094 int cmd;
08095 char *buf;
08096
08097 buf = ast_alloca(strlen(box) + 2);
08098 strcpy(buf, box);
08099 strcat(buf, "s");
08100
08101 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08102 cmd = ast_play_and_wait(chan, buf);
08103 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08104 } else {
08105 cmd = ast_play_and_wait(chan, "vm-messages");
08106 return cmd ? cmd : ast_play_and_wait(chan, box);
08107 }
08108 }
08109
08110 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08111 {
08112 int cmd;
08113
08114 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08115 if (!strcasecmp(box, "vm-INBOX"))
08116 cmd = ast_play_and_wait(chan, "vm-new-e");
08117 else
08118 cmd = ast_play_and_wait(chan, "vm-old-e");
08119 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08120 } else {
08121 cmd = ast_play_and_wait(chan, "vm-messages");
08122 return cmd ? cmd : ast_play_and_wait(chan, box);
08123 }
08124 }
08125
08126 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08127 {
08128 int cmd;
08129
08130 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08131 cmd = ast_play_and_wait(chan, "vm-messages");
08132 return cmd ? cmd : ast_play_and_wait(chan, box);
08133 } else {
08134 cmd = ast_play_and_wait(chan, box);
08135 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08136 }
08137 }
08138
08139 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08140 {
08141 int cmd;
08142
08143 if ( !strncasecmp(chan->language, "it", 2) ||
08144 !strncasecmp(chan->language, "es", 2) ||
08145 !strncasecmp(chan->language, "pt", 2)) {
08146 cmd = ast_play_and_wait(chan, "vm-messages");
08147 return cmd ? cmd : ast_play_and_wait(chan, box);
08148 } else if (!strncasecmp(chan->language, "gr", 2)) {
08149 return vm_play_folder_name_gr(chan, box);
08150 } else if (!strncasecmp(chan->language, "he", 2)) {
08151 return ast_play_and_wait(chan, box);
08152 } else if (!strncasecmp(chan->language, "pl", 2)) {
08153 return vm_play_folder_name_pl(chan, box);
08154 } else if (!strncasecmp(chan->language, "ua", 2)) {
08155 return vm_play_folder_name_ua(chan, box);
08156 } else if (!strncasecmp(chan->language, "vi", 2)) {
08157 return ast_play_and_wait(chan, box);
08158 } else {
08159 cmd = ast_play_and_wait(chan, box);
08160 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08161 }
08162 }
08163
08164
08165
08166
08167
08168
08169
08170
08171
08172
08173
08174
08175
08176 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08177 {
08178 int res = 0;
08179
08180 if (vms->newmessages) {
08181 res = ast_play_and_wait(chan, "vm-youhave");
08182 if (!res)
08183 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
08184 if (!res) {
08185 if ((vms->newmessages == 1)) {
08186 res = ast_play_and_wait(chan, "vm-INBOX");
08187 if (!res)
08188 res = ast_play_and_wait(chan, "vm-message");
08189 } else {
08190 res = ast_play_and_wait(chan, "vm-INBOXs");
08191 if (!res)
08192 res = ast_play_and_wait(chan, "vm-messages");
08193 }
08194 }
08195 } else if (vms->oldmessages){
08196 res = ast_play_and_wait(chan, "vm-youhave");
08197 if (!res)
08198 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
08199 if ((vms->oldmessages == 1)){
08200 res = ast_play_and_wait(chan, "vm-Old");
08201 if (!res)
08202 res = ast_play_and_wait(chan, "vm-message");
08203 } else {
08204 res = ast_play_and_wait(chan, "vm-Olds");
08205 if (!res)
08206 res = ast_play_and_wait(chan, "vm-messages");
08207 }
08208 } else if (!vms->oldmessages && !vms->newmessages)
08209 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08210 return res;
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
08252
08253
08254
08255
08256
08257
08258
08259
08260
08261
08262
08263
08264
08265
08266
08267
08268
08269
08270 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08271 {
08272 int res;
08273 int lastnum = 0;
08274
08275 res = ast_play_and_wait(chan, "vm-youhave");
08276
08277 if (!res && vms->newmessages) {
08278 lastnum = vms->newmessages;
08279
08280 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08281 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08282 }
08283
08284 if (!res && vms->oldmessages) {
08285 res = ast_play_and_wait(chan, "vm-and");
08286 }
08287 }
08288
08289 if (!res && vms->oldmessages) {
08290 lastnum = vms->oldmessages;
08291
08292 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08293 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08294 }
08295 }
08296
08297 if (!res) {
08298 if (lastnum == 0) {
08299 res = ast_play_and_wait(chan, "vm-no");
08300 }
08301 if (!res) {
08302 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08303 }
08304 }
08305
08306 return res;
08307 }
08308
08309
08310 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08311 {
08312 int res = 0;
08313
08314
08315 if (!res) {
08316 if ((vms->newmessages) || (vms->oldmessages)) {
08317 res = ast_play_and_wait(chan, "vm-youhave");
08318 }
08319
08320
08321
08322
08323
08324 if (vms->newmessages) {
08325 if (!res) {
08326 if (vms->newmessages == 1) {
08327 res = ast_play_and_wait(chan, "vm-INBOX1");
08328 } else {
08329 if (vms->newmessages == 2) {
08330 res = ast_play_and_wait(chan, "vm-shtei");
08331 } else {
08332 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08333 }
08334 res = ast_play_and_wait(chan, "vm-INBOX");
08335 }
08336 }
08337 if (vms->oldmessages && !res) {
08338 res = ast_play_and_wait(chan, "vm-and");
08339 if (vms->oldmessages == 1) {
08340 res = ast_play_and_wait(chan, "vm-Old1");
08341 } else {
08342 if (vms->oldmessages == 2) {
08343 res = ast_play_and_wait(chan, "vm-shtei");
08344 } else {
08345 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08346 }
08347 res = ast_play_and_wait(chan, "vm-Old");
08348 }
08349 }
08350 }
08351 if (!res && vms->oldmessages && !vms->newmessages) {
08352 if (!res) {
08353 if (vms->oldmessages == 1) {
08354 res = ast_play_and_wait(chan, "vm-Old1");
08355 } else {
08356 if (vms->oldmessages == 2) {
08357 res = ast_play_and_wait(chan, "vm-shtei");
08358 } else {
08359 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08360 }
08361 res = ast_play_and_wait(chan, "vm-Old");
08362 }
08363 }
08364 }
08365 if (!res) {
08366 if (!vms->oldmessages && !vms->newmessages) {
08367 if (!res) {
08368 res = ast_play_and_wait(chan, "vm-nomessages");
08369 }
08370 }
08371 }
08372 }
08373 return res;
08374 }
08375
08376
08377 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08378 {
08379 int res;
08380
08381
08382 res = ast_play_and_wait(chan, "vm-youhave");
08383 if (!res) {
08384 if (vms->urgentmessages) {
08385 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08386 if (!res)
08387 res = ast_play_and_wait(chan, "vm-Urgent");
08388 if ((vms->oldmessages || vms->newmessages) && !res) {
08389 res = ast_play_and_wait(chan, "vm-and");
08390 } else if (!res) {
08391 if ((vms->urgentmessages == 1))
08392 res = ast_play_and_wait(chan, "vm-message");
08393 else
08394 res = ast_play_and_wait(chan, "vm-messages");
08395 }
08396 }
08397 if (vms->newmessages) {
08398 res = say_and_wait(chan, vms->newmessages, chan->language);
08399 if (!res)
08400 res = ast_play_and_wait(chan, "vm-INBOX");
08401 if (vms->oldmessages && !res)
08402 res = ast_play_and_wait(chan, "vm-and");
08403 else if (!res) {
08404 if ((vms->newmessages == 1))
08405 res = ast_play_and_wait(chan, "vm-message");
08406 else
08407 res = ast_play_and_wait(chan, "vm-messages");
08408 }
08409
08410 }
08411 if (!res && vms->oldmessages) {
08412 res = say_and_wait(chan, vms->oldmessages, chan->language);
08413 if (!res)
08414 res = ast_play_and_wait(chan, "vm-Old");
08415 if (!res) {
08416 if (vms->oldmessages == 1)
08417 res = ast_play_and_wait(chan, "vm-message");
08418 else
08419 res = ast_play_and_wait(chan, "vm-messages");
08420 }
08421 }
08422 if (!res) {
08423 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08424 res = ast_play_and_wait(chan, "vm-no");
08425 if (!res)
08426 res = ast_play_and_wait(chan, "vm-messages");
08427 }
08428 }
08429 }
08430 return res;
08431 }
08432
08433
08434 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08435 {
08436
08437 int res;
08438 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08439 res = ast_play_and_wait(chan, "vm-no") ||
08440 ast_play_and_wait(chan, "vm-message");
08441 else
08442 res = ast_play_and_wait(chan, "vm-youhave");
08443 if (!res && vms->newmessages) {
08444 res = (vms->newmessages == 1) ?
08445 ast_play_and_wait(chan, "digits/un") ||
08446 ast_play_and_wait(chan, "vm-nuovo") ||
08447 ast_play_and_wait(chan, "vm-message") :
08448
08449 say_and_wait(chan, vms->newmessages, chan->language) ||
08450 ast_play_and_wait(chan, "vm-nuovi") ||
08451 ast_play_and_wait(chan, "vm-messages");
08452 if (!res && vms->oldmessages)
08453 res = ast_play_and_wait(chan, "vm-and");
08454 }
08455 if (!res && vms->oldmessages) {
08456 res = (vms->oldmessages == 1) ?
08457 ast_play_and_wait(chan, "digits/un") ||
08458 ast_play_and_wait(chan, "vm-vecchio") ||
08459 ast_play_and_wait(chan, "vm-message") :
08460
08461 say_and_wait(chan, vms->oldmessages, chan->language) ||
08462 ast_play_and_wait(chan, "vm-vecchi") ||
08463 ast_play_and_wait(chan, "vm-messages");
08464 }
08465 return res;
08466 }
08467
08468
08469 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08470 {
08471
08472 int res;
08473 div_t num;
08474
08475 if (!vms->oldmessages && !vms->newmessages) {
08476 res = ast_play_and_wait(chan, "vm-no");
08477 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08478 return res;
08479 } else {
08480 res = ast_play_and_wait(chan, "vm-youhave");
08481 }
08482
08483 if (vms->newmessages) {
08484 num = div(vms->newmessages, 10);
08485 if (vms->newmessages == 1) {
08486 res = ast_play_and_wait(chan, "digits/1-a");
08487 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08488 res = res ? res : ast_play_and_wait(chan, "vm-message");
08489 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08490 if (num.rem == 2) {
08491 if (!num.quot) {
08492 res = ast_play_and_wait(chan, "digits/2-ie");
08493 } else {
08494 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08495 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08496 }
08497 } else {
08498 res = say_and_wait(chan, vms->newmessages, chan->language);
08499 }
08500 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08501 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08502 } else {
08503 res = say_and_wait(chan, vms->newmessages, chan->language);
08504 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08505 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08506 }
08507 if (!res && vms->oldmessages)
08508 res = ast_play_and_wait(chan, "vm-and");
08509 }
08510 if (!res && vms->oldmessages) {
08511 num = div(vms->oldmessages, 10);
08512 if (vms->oldmessages == 1) {
08513 res = ast_play_and_wait(chan, "digits/1-a");
08514 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08515 res = res ? res : ast_play_and_wait(chan, "vm-message");
08516 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08517 if (num.rem == 2) {
08518 if (!num.quot) {
08519 res = ast_play_and_wait(chan, "digits/2-ie");
08520 } else {
08521 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08522 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08523 }
08524 } else {
08525 res = say_and_wait(chan, vms->oldmessages, chan->language);
08526 }
08527 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08528 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08529 } else {
08530 res = say_and_wait(chan, vms->oldmessages, chan->language);
08531 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08532 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08533 }
08534 }
08535
08536 return res;
08537 }
08538
08539
08540 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08541 {
08542
08543 int res;
08544
08545 res = ast_play_and_wait(chan, "vm-youhave");
08546 if (res)
08547 return res;
08548
08549 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08550 res = ast_play_and_wait(chan, "vm-no");
08551 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08552 return res;
08553 }
08554
08555 if (vms->newmessages) {
08556 if ((vms->newmessages == 1)) {
08557 res = ast_play_and_wait(chan, "digits/ett");
08558 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08559 res = res ? res : ast_play_and_wait(chan, "vm-message");
08560 } else {
08561 res = say_and_wait(chan, vms->newmessages, chan->language);
08562 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08563 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08564 }
08565 if (!res && vms->oldmessages)
08566 res = ast_play_and_wait(chan, "vm-and");
08567 }
08568 if (!res && vms->oldmessages) {
08569 if (vms->oldmessages == 1) {
08570 res = ast_play_and_wait(chan, "digits/ett");
08571 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08572 res = res ? res : ast_play_and_wait(chan, "vm-message");
08573 } else {
08574 res = say_and_wait(chan, vms->oldmessages, chan->language);
08575 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08576 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08577 }
08578 }
08579
08580 return res;
08581 }
08582
08583
08584 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08585 {
08586
08587 int res;
08588
08589 res = ast_play_and_wait(chan, "vm-youhave");
08590 if (res)
08591 return res;
08592
08593 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08594 res = ast_play_and_wait(chan, "vm-no");
08595 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08596 return res;
08597 }
08598
08599 if (vms->newmessages) {
08600 if ((vms->newmessages == 1)) {
08601 res = ast_play_and_wait(chan, "digits/1");
08602 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08603 res = res ? res : ast_play_and_wait(chan, "vm-message");
08604 } else {
08605 res = say_and_wait(chan, vms->newmessages, chan->language);
08606 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08607 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08608 }
08609 if (!res && vms->oldmessages)
08610 res = ast_play_and_wait(chan, "vm-and");
08611 }
08612 if (!res && vms->oldmessages) {
08613 if (vms->oldmessages == 1) {
08614 res = ast_play_and_wait(chan, "digits/1");
08615 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08616 res = res ? res : ast_play_and_wait(chan, "vm-message");
08617 } else {
08618 res = say_and_wait(chan, vms->oldmessages, chan->language);
08619 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08620 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08621 }
08622 }
08623
08624 return res;
08625 }
08626
08627
08628 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08629 {
08630
08631 int res;
08632 res = ast_play_and_wait(chan, "vm-youhave");
08633 if (!res) {
08634 if (vms->newmessages) {
08635 if ((vms->newmessages == 1))
08636 res = ast_play_and_wait(chan, "digits/1F");
08637 else
08638 res = say_and_wait(chan, vms->newmessages, chan->language);
08639 if (!res)
08640 res = ast_play_and_wait(chan, "vm-INBOX");
08641 if (vms->oldmessages && !res)
08642 res = ast_play_and_wait(chan, "vm-and");
08643 else if (!res) {
08644 if ((vms->newmessages == 1))
08645 res = ast_play_and_wait(chan, "vm-message");
08646 else
08647 res = ast_play_and_wait(chan, "vm-messages");
08648 }
08649
08650 }
08651 if (!res && vms->oldmessages) {
08652 if (vms->oldmessages == 1)
08653 res = ast_play_and_wait(chan, "digits/1F");
08654 else
08655 res = say_and_wait(chan, vms->oldmessages, chan->language);
08656 if (!res)
08657 res = ast_play_and_wait(chan, "vm-Old");
08658 if (!res) {
08659 if (vms->oldmessages == 1)
08660 res = ast_play_and_wait(chan, "vm-message");
08661 else
08662 res = ast_play_and_wait(chan, "vm-messages");
08663 }
08664 }
08665 if (!res) {
08666 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08667 res = ast_play_and_wait(chan, "vm-no");
08668 if (!res)
08669 res = ast_play_and_wait(chan, "vm-messages");
08670 }
08671 }
08672 }
08673 return res;
08674 }
08675
08676
08677 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08678 {
08679
08680 int res;
08681 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08682 res = ast_play_and_wait(chan, "vm-youhaveno");
08683 if (!res)
08684 res = ast_play_and_wait(chan, "vm-messages");
08685 } else {
08686 res = ast_play_and_wait(chan, "vm-youhave");
08687 }
08688 if (!res) {
08689 if (vms->newmessages) {
08690 if (!res) {
08691 if ((vms->newmessages == 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-INBOXs");
08697 } else {
08698 res = say_and_wait(chan, vms->newmessages, 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-INBOX");
08703 }
08704 }
08705 if (vms->oldmessages && !res)
08706 res = ast_play_and_wait(chan, "vm-and");
08707 }
08708 if (vms->oldmessages) {
08709 if (!res) {
08710 if (vms->oldmessages == 1) {
08711 res = ast_play_and_wait(chan, "digits/1M");
08712 if (!res)
08713 res = ast_play_and_wait(chan, "vm-message");
08714 if (!res)
08715 res = ast_play_and_wait(chan, "vm-Olds");
08716 } else {
08717 res = say_and_wait(chan, vms->oldmessages, chan->language);
08718 if (!res)
08719 res = ast_play_and_wait(chan, "vm-messages");
08720 if (!res)
08721 res = ast_play_and_wait(chan, "vm-Old");
08722 }
08723 }
08724 }
08725 }
08726 return res;
08727 }
08728
08729
08730 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08731
08732 int res;
08733 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08734 res = ast_play_and_wait(chan, "vm-nomessages");
08735 return res;
08736 } else {
08737 res = ast_play_and_wait(chan, "vm-youhave");
08738 }
08739 if (vms->newmessages) {
08740 if (!res)
08741 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08742 if ((vms->newmessages == 1)) {
08743 if (!res)
08744 res = ast_play_and_wait(chan, "vm-message");
08745 if (!res)
08746 res = ast_play_and_wait(chan, "vm-INBOXs");
08747 } else {
08748 if (!res)
08749 res = ast_play_and_wait(chan, "vm-messages");
08750 if (!res)
08751 res = ast_play_and_wait(chan, "vm-INBOX");
08752 }
08753 if (vms->oldmessages && !res)
08754 res = ast_play_and_wait(chan, "vm-and");
08755 }
08756 if (vms->oldmessages) {
08757 if (!res)
08758 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08759 if (vms->oldmessages == 1) {
08760 if (!res)
08761 res = ast_play_and_wait(chan, "vm-message");
08762 if (!res)
08763 res = ast_play_and_wait(chan, "vm-Olds");
08764 } else {
08765 if (!res)
08766 res = ast_play_and_wait(chan, "vm-messages");
08767 if (!res)
08768 res = ast_play_and_wait(chan, "vm-Old");
08769 }
08770 }
08771 return res;
08772 }
08773
08774
08775 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08776 {
08777
08778 int res;
08779 res = ast_play_and_wait(chan, "vm-youhave");
08780 if (!res) {
08781 if (vms->newmessages) {
08782 res = say_and_wait(chan, vms->newmessages, chan->language);
08783 if (!res)
08784 res = ast_play_and_wait(chan, "vm-INBOX");
08785 if (vms->oldmessages && !res)
08786 res = ast_play_and_wait(chan, "vm-and");
08787 else if (!res) {
08788 if ((vms->newmessages == 1))
08789 res = ast_play_and_wait(chan, "vm-message");
08790 else
08791 res = ast_play_and_wait(chan, "vm-messages");
08792 }
08793
08794 }
08795 if (!res && vms->oldmessages) {
08796 res = say_and_wait(chan, vms->oldmessages, chan->language);
08797 if (!res)
08798 res = ast_play_and_wait(chan, "vm-Old");
08799 if (!res) {
08800 if (vms->oldmessages == 1)
08801 res = ast_play_and_wait(chan, "vm-message");
08802 else
08803 res = ast_play_and_wait(chan, "vm-messages");
08804 }
08805 }
08806 if (!res) {
08807 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08808 res = ast_play_and_wait(chan, "vm-no");
08809 if (!res)
08810 res = ast_play_and_wait(chan, "vm-messages");
08811 }
08812 }
08813 }
08814 return res;
08815 }
08816
08817
08818 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08819 {
08820
08821 int res;
08822 res = ast_play_and_wait(chan, "vm-youhave");
08823 if (!res) {
08824 if (vms->newmessages) {
08825 res = say_and_wait(chan, vms->newmessages, chan->language);
08826 if (!res) {
08827 if (vms->newmessages == 1)
08828 res = ast_play_and_wait(chan, "vm-INBOXs");
08829 else
08830 res = ast_play_and_wait(chan, "vm-INBOX");
08831 }
08832 if (vms->oldmessages && !res)
08833 res = ast_play_and_wait(chan, "vm-and");
08834 else if (!res) {
08835 if ((vms->newmessages == 1))
08836 res = ast_play_and_wait(chan, "vm-message");
08837 else
08838 res = ast_play_and_wait(chan, "vm-messages");
08839 }
08840
08841 }
08842 if (!res && vms->oldmessages) {
08843 res = say_and_wait(chan, vms->oldmessages, chan->language);
08844 if (!res) {
08845 if (vms->oldmessages == 1)
08846 res = ast_play_and_wait(chan, "vm-Olds");
08847 else
08848 res = ast_play_and_wait(chan, "vm-Old");
08849 }
08850 if (!res) {
08851 if (vms->oldmessages == 1)
08852 res = ast_play_and_wait(chan, "vm-message");
08853 else
08854 res = ast_play_and_wait(chan, "vm-messages");
08855 }
08856 }
08857 if (!res) {
08858 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08859 res = ast_play_and_wait(chan, "vm-no");
08860 if (!res)
08861 res = ast_play_and_wait(chan, "vm-messages");
08862 }
08863 }
08864 }
08865 return res;
08866 }
08867
08868
08869 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08870 {
08871
08872 int res;
08873 res = ast_play_and_wait(chan, "vm-youhave");
08874 if (!res) {
08875 if (vms->newmessages) {
08876 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08877 if (!res) {
08878 if ((vms->newmessages == 1)) {
08879 res = ast_play_and_wait(chan, "vm-message");
08880 if (!res)
08881 res = ast_play_and_wait(chan, "vm-INBOXs");
08882 } else {
08883 res = ast_play_and_wait(chan, "vm-messages");
08884 if (!res)
08885 res = ast_play_and_wait(chan, "vm-INBOX");
08886 }
08887 }
08888 if (vms->oldmessages && !res)
08889 res = ast_play_and_wait(chan, "vm-and");
08890 }
08891 if (!res && vms->oldmessages) {
08892 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08893 if (!res) {
08894 if (vms->oldmessages == 1) {
08895 res = ast_play_and_wait(chan, "vm-message");
08896 if (!res)
08897 res = ast_play_and_wait(chan, "vm-Olds");
08898 } else {
08899 res = ast_play_and_wait(chan, "vm-messages");
08900 if (!res)
08901 res = ast_play_and_wait(chan, "vm-Old");
08902 }
08903 }
08904 }
08905 if (!res) {
08906 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08907 res = ast_play_and_wait(chan, "vm-no");
08908 if (!res)
08909 res = ast_play_and_wait(chan, "vm-messages");
08910 }
08911 }
08912 }
08913 return res;
08914 }
08915
08916
08917
08918
08919
08920
08921
08922
08923
08924
08925
08926
08927
08928
08929
08930
08931
08932 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08933 {
08934 int res;
08935 res = ast_play_and_wait(chan, "vm-youhave");
08936 if (!res) {
08937 if (vms->newmessages) {
08938 if (vms->newmessages == 1) {
08939 res = ast_play_and_wait(chan, "digits/jednu");
08940 } else {
08941 res = say_and_wait(chan, vms->newmessages, chan->language);
08942 }
08943 if (!res) {
08944 if ((vms->newmessages == 1))
08945 res = ast_play_and_wait(chan, "vm-novou");
08946 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08947 res = ast_play_and_wait(chan, "vm-nove");
08948 if (vms->newmessages > 4)
08949 res = ast_play_and_wait(chan, "vm-novych");
08950 }
08951 if (vms->oldmessages && !res)
08952 res = ast_play_and_wait(chan, "vm-and");
08953 else if (!res) {
08954 if ((vms->newmessages == 1))
08955 res = ast_play_and_wait(chan, "vm-zpravu");
08956 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08957 res = ast_play_and_wait(chan, "vm-zpravy");
08958 if (vms->newmessages > 4)
08959 res = ast_play_and_wait(chan, "vm-zprav");
08960 }
08961 }
08962 if (!res && vms->oldmessages) {
08963 res = say_and_wait(chan, vms->oldmessages, chan->language);
08964 if (!res) {
08965 if ((vms->oldmessages == 1))
08966 res = ast_play_and_wait(chan, "vm-starou");
08967 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08968 res = ast_play_and_wait(chan, "vm-stare");
08969 if (vms->oldmessages > 4)
08970 res = ast_play_and_wait(chan, "vm-starych");
08971 }
08972 if (!res) {
08973 if ((vms->oldmessages == 1))
08974 res = ast_play_and_wait(chan, "vm-zpravu");
08975 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08976 res = ast_play_and_wait(chan, "vm-zpravy");
08977 if (vms->oldmessages > 4)
08978 res = ast_play_and_wait(chan, "vm-zprav");
08979 }
08980 }
08981 if (!res) {
08982 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08983 res = ast_play_and_wait(chan, "vm-no");
08984 if (!res)
08985 res = ast_play_and_wait(chan, "vm-zpravy");
08986 }
08987 }
08988 }
08989 return res;
08990 }
08991
08992
08993 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
08994 {
08995 int res;
08996
08997 res = ast_play_and_wait(chan, "vm-you");
08998
08999 if (!res && vms->newmessages) {
09000 res = ast_play_and_wait(chan, "vm-have");
09001 if (!res)
09002 res = say_and_wait(chan, vms->newmessages, chan->language);
09003 if (!res)
09004 res = ast_play_and_wait(chan, "vm-tong");
09005 if (!res)
09006 res = ast_play_and_wait(chan, "vm-INBOX");
09007 if (vms->oldmessages && !res)
09008 res = ast_play_and_wait(chan, "vm-and");
09009 else if (!res)
09010 res = ast_play_and_wait(chan, "vm-messages");
09011 }
09012 if (!res && vms->oldmessages) {
09013 res = ast_play_and_wait(chan, "vm-have");
09014 if (!res)
09015 res = say_and_wait(chan, vms->oldmessages, chan->language);
09016 if (!res)
09017 res = ast_play_and_wait(chan, "vm-tong");
09018 if (!res)
09019 res = ast_play_and_wait(chan, "vm-Old");
09020 if (!res)
09021 res = ast_play_and_wait(chan, "vm-messages");
09022 }
09023 if (!res && !vms->oldmessages && !vms->newmessages) {
09024 res = ast_play_and_wait(chan, "vm-haveno");
09025 if (!res)
09026 res = ast_play_and_wait(chan, "vm-messages");
09027 }
09028 return res;
09029 }
09030
09031
09032 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
09033 {
09034 int res;
09035
09036
09037 res = ast_play_and_wait(chan, "vm-youhave");
09038 if (!res) {
09039 if (vms->newmessages) {
09040 res = say_and_wait(chan, vms->newmessages, chan->language);
09041 if (!res)
09042 res = ast_play_and_wait(chan, "vm-INBOX");
09043 if (vms->oldmessages && !res)
09044 res = ast_play_and_wait(chan, "vm-and");
09045 }
09046 if (!res && vms->oldmessages) {
09047 res = say_and_wait(chan, vms->oldmessages, chan->language);
09048 if (!res)
09049 res = ast_play_and_wait(chan, "vm-Old");
09050 }
09051 if (!res) {
09052 if (!vms->oldmessages && !vms->newmessages) {
09053 res = ast_play_and_wait(chan, "vm-no");
09054 if (!res)
09055 res = ast_play_and_wait(chan, "vm-message");
09056 }
09057 }
09058 }
09059 return res;
09060 }
09061
09062 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
09063 {
09064 char prefile[256];
09065
09066
09067 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09068 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
09069 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09070 if (ast_fileexists(prefile, NULL, NULL) > 0) {
09071 ast_play_and_wait(chan, "vm-tempgreetactive");
09072 }
09073 DISPOSE(prefile, -1);
09074 }
09075
09076
09077 if (0) {
09078 return 0;
09079 } else if (!strncasecmp(chan->language, "cs", 2)) {
09080 return vm_intro_cs(chan, vms);
09081 } else if (!strncasecmp(chan->language, "cz", 2)) {
09082 static int deprecation_warning = 0;
09083 if (deprecation_warning++ % 10 == 0) {
09084 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09085 }
09086 return vm_intro_cs(chan, vms);
09087 } else if (!strncasecmp(chan->language, "de", 2)) {
09088 return vm_intro_de(chan, vms);
09089 } else if (!strncasecmp(chan->language, "es", 2)) {
09090 return vm_intro_es(chan, vms);
09091 } else if (!strncasecmp(chan->language, "fr", 2)) {
09092 return vm_intro_fr(chan, vms);
09093 } else if (!strncasecmp(chan->language, "gr", 2)) {
09094 return vm_intro_gr(chan, vms);
09095 } else if (!strncasecmp(chan->language, "he", 2)) {
09096 return vm_intro_he(chan, vms);
09097 } else if (!strncasecmp(chan->language, "it", 2)) {
09098 return vm_intro_it(chan, vms);
09099 } else if (!strncasecmp(chan->language, "nl", 2)) {
09100 return vm_intro_nl(chan, vms);
09101 } else if (!strncasecmp(chan->language, "no", 2)) {
09102 return vm_intro_no(chan, vms);
09103 } else if (!strncasecmp(chan->language, "pl", 2)) {
09104 return vm_intro_pl(chan, vms);
09105 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
09106 return vm_intro_pt_BR(chan, vms);
09107 } else if (!strncasecmp(chan->language, "pt", 2)) {
09108 return vm_intro_pt(chan, vms);
09109 } else if (!strncasecmp(chan->language, "ru", 2)) {
09110 return vm_intro_multilang(chan, vms, "n");
09111 } else if (!strncasecmp(chan->language, "se", 2)) {
09112 return vm_intro_se(chan, vms);
09113 } else if (!strncasecmp(chan->language, "ua", 2)) {
09114 return vm_intro_multilang(chan, vms, "n");
09115 } else if (!strncasecmp(chan->language, "vi", 2)) {
09116 return vm_intro_vi(chan, vms);
09117 } else if (!strncasecmp(chan->language, "zh", 2)) {
09118 return vm_intro_zh(chan, vms);
09119 } else {
09120 return vm_intro_en(chan, vms);
09121 }
09122 }
09123
09124 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09125 {
09126 int res = 0;
09127
09128 while (!res) {
09129 if (vms->starting) {
09130 if (vms->lastmsg > -1) {
09131 if (skipadvanced)
09132 res = ast_play_and_wait(chan, "vm-onefor-full");
09133 else
09134 res = ast_play_and_wait(chan, "vm-onefor");
09135 if (!res)
09136 res = vm_play_folder_name(chan, vms->vmbox);
09137 }
09138 if (!res) {
09139 if (skipadvanced)
09140 res = ast_play_and_wait(chan, "vm-opts-full");
09141 else
09142 res = ast_play_and_wait(chan, "vm-opts");
09143 }
09144 } else {
09145
09146 if (skipadvanced) {
09147 res = ast_play_and_wait(chan, "vm-onefor-full");
09148 if (!res)
09149 res = vm_play_folder_name(chan, vms->vmbox);
09150 res = ast_play_and_wait(chan, "vm-opts-full");
09151 }
09152
09153
09154
09155
09156
09157
09158 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09159 res = ast_play_and_wait(chan, "vm-prev");
09160 }
09161 if (!res && !skipadvanced)
09162 res = ast_play_and_wait(chan, "vm-advopts");
09163 if (!res)
09164 res = ast_play_and_wait(chan, "vm-repeat");
09165
09166
09167
09168
09169
09170
09171 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09172 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09173 res = ast_play_and_wait(chan, "vm-next");
09174 }
09175 if (!res) {
09176 int curmsg_deleted;
09177 #ifdef IMAP_STORAGE
09178 ast_mutex_lock(&vms->lock);
09179 #endif
09180 curmsg_deleted = vms->deleted[vms->curmsg];
09181 #ifdef IMAP_STORAGE
09182 ast_mutex_unlock(&vms->lock);
09183 #endif
09184 if (!curmsg_deleted) {
09185 res = ast_play_and_wait(chan, "vm-delete");
09186 } else {
09187 res = ast_play_and_wait(chan, "vm-undelete");
09188 }
09189 if (!res) {
09190 res = ast_play_and_wait(chan, "vm-toforward");
09191 }
09192 if (!res) {
09193 res = ast_play_and_wait(chan, "vm-savemessage");
09194 }
09195 }
09196 }
09197 if (!res) {
09198 res = ast_play_and_wait(chan, "vm-helpexit");
09199 }
09200 if (!res)
09201 res = ast_waitfordigit(chan, 6000);
09202 if (!res) {
09203 vms->repeats++;
09204 if (vms->repeats > 2) {
09205 res = 't';
09206 }
09207 }
09208 }
09209 return res;
09210 }
09211
09212 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09213 {
09214 int res = 0;
09215
09216 while (!res) {
09217 if (vms->lastmsg > -1) {
09218 res = ast_play_and_wait(chan, "vm-listen");
09219 if (!res)
09220 res = vm_play_folder_name(chan, vms->vmbox);
09221 if (!res)
09222 res = ast_play_and_wait(chan, "press");
09223 if (!res)
09224 res = ast_play_and_wait(chan, "digits/1");
09225 }
09226 if (!res)
09227 res = ast_play_and_wait(chan, "vm-opts");
09228 if (!res) {
09229 vms->starting = 0;
09230 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09231 }
09232 }
09233 return res;
09234 }
09235
09236 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09237 {
09238 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
09239 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09240 } else {
09241 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09242 }
09243 }
09244
09245
09246 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09247 {
09248 int cmd = 0;
09249 int duration = 0;
09250 int tries = 0;
09251 char newpassword[80] = "";
09252 char newpassword2[80] = "";
09253 char prefile[PATH_MAX] = "";
09254 unsigned char buf[256];
09255 int bytes = 0;
09256
09257 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09258 if (ast_adsi_available(chan)) {
09259 bytes += adsi_logo(buf + bytes);
09260 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09261 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09262 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09263 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09264 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09265 }
09266
09267
09268 if (ast_test_flag(vmu, VM_FORCENAME)) {
09269 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09270 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09271 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09272 if (cmd < 0 || cmd == 't' || cmd == '#')
09273 return cmd;
09274 }
09275 }
09276
09277
09278 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09279 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09280 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09281 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09282 if (cmd < 0 || cmd == 't' || cmd == '#')
09283 return cmd;
09284 }
09285
09286 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09287 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09288 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09289 if (cmd < 0 || cmd == 't' || cmd == '#')
09290 return cmd;
09291 }
09292 }
09293
09294
09295
09296
09297
09298 for (;;) {
09299 newpassword[1] = '\0';
09300 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09301 if (cmd == '#')
09302 newpassword[0] = '\0';
09303 if (cmd < 0 || cmd == 't' || cmd == '#')
09304 return cmd;
09305 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09306 if (cmd < 0 || cmd == 't' || cmd == '#')
09307 return cmd;
09308 cmd = check_password(vmu, newpassword);
09309 if (cmd != 0) {
09310 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09311 cmd = ast_play_and_wait(chan, vm_invalid_password);
09312 } else {
09313 newpassword2[1] = '\0';
09314 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09315 if (cmd == '#')
09316 newpassword2[0] = '\0';
09317 if (cmd < 0 || cmd == 't' || cmd == '#')
09318 return cmd;
09319 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09320 if (cmd < 0 || cmd == 't' || cmd == '#')
09321 return cmd;
09322 if (!strcmp(newpassword, newpassword2))
09323 break;
09324 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09325 cmd = ast_play_and_wait(chan, vm_mismatch);
09326 }
09327 if (++tries == 3)
09328 return -1;
09329 if (cmd != 0) {
09330 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09331 }
09332 }
09333 if (pwdchange & PWDCHANGE_INTERNAL)
09334 vm_change_password(vmu, newpassword);
09335 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09336 vm_change_password_shell(vmu, newpassword);
09337
09338 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09339 cmd = ast_play_and_wait(chan, vm_passchanged);
09340
09341 return cmd;
09342 }
09343
09344 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09345 {
09346 int cmd = 0;
09347 int retries = 0;
09348 int duration = 0;
09349 char newpassword[80] = "";
09350 char newpassword2[80] = "";
09351 char prefile[PATH_MAX] = "";
09352 unsigned char buf[256];
09353 int bytes = 0;
09354
09355 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
09356 if (ast_adsi_available(chan)) {
09357 bytes += adsi_logo(buf + bytes);
09358 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09359 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09360 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09361 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09362 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09363 }
09364 while ((cmd >= 0) && (cmd != 't')) {
09365 if (cmd)
09366 retries = 0;
09367 switch (cmd) {
09368 case '1':
09369 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09370 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09371 break;
09372 case '2':
09373 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09374 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09375 break;
09376 case '3':
09377 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09378 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09379 break;
09380 case '4':
09381 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09382 break;
09383 case '5':
09384 if (vmu->password[0] == '-') {
09385 cmd = ast_play_and_wait(chan, "vm-no");
09386 break;
09387 }
09388 newpassword[1] = '\0';
09389 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09390 if (cmd == '#')
09391 newpassword[0] = '\0';
09392 else {
09393 if (cmd < 0)
09394 break;
09395 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09396 break;
09397 }
09398 }
09399 cmd = check_password(vmu, newpassword);
09400 if (cmd != 0) {
09401 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09402 cmd = ast_play_and_wait(chan, vm_invalid_password);
09403 if (!cmd) {
09404 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09405 }
09406 break;
09407 }
09408 newpassword2[1] = '\0';
09409 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09410 if (cmd == '#')
09411 newpassword2[0] = '\0';
09412 else {
09413 if (cmd < 0)
09414 break;
09415
09416 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09417 break;
09418 }
09419 }
09420 if (strcmp(newpassword, newpassword2)) {
09421 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09422 cmd = ast_play_and_wait(chan, vm_mismatch);
09423 if (!cmd) {
09424 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09425 }
09426 break;
09427 }
09428
09429 if (pwdchange & PWDCHANGE_INTERNAL) {
09430 vm_change_password(vmu, newpassword);
09431 }
09432 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
09433 vm_change_password_shell(vmu, newpassword);
09434 }
09435
09436 ast_debug(1, "User %s set password to %s of length %d\n",
09437 vms->username, newpassword, (int) strlen(newpassword));
09438 cmd = ast_play_and_wait(chan, vm_passchanged);
09439 break;
09440 case '*':
09441 cmd = 't';
09442 break;
09443 default:
09444 cmd = 0;
09445 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09446 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09447 if (ast_fileexists(prefile, NULL, NULL)) {
09448 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09449 }
09450 DISPOSE(prefile, -1);
09451 if (!cmd) {
09452 cmd = ast_play_and_wait(chan, "vm-options");
09453 }
09454 if (!cmd) {
09455 cmd = ast_waitfordigit(chan, 6000);
09456 }
09457 if (!cmd) {
09458 retries++;
09459 }
09460 if (retries > 3) {
09461 cmd = 't';
09462 }
09463 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09464 }
09465 }
09466 if (cmd == 't')
09467 cmd = 0;
09468 return cmd;
09469 }
09470
09471
09472
09473
09474
09475
09476
09477
09478
09479
09480
09481
09482
09483
09484
09485
09486
09487 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09488 {
09489 int cmd = 0;
09490 int retries = 0;
09491 int duration = 0;
09492 char prefile[PATH_MAX] = "";
09493 unsigned char buf[256];
09494 int bytes = 0;
09495
09496 if (ast_adsi_available(chan)) {
09497 bytes += adsi_logo(buf + bytes);
09498 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09499 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09500 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09501 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09502 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09503 }
09504
09505 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
09506 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09507 while ((cmd >= 0) && (cmd != 't')) {
09508 if (cmd)
09509 retries = 0;
09510 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09511 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09512 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09513 if (cmd == -1) {
09514 break;
09515 }
09516 cmd = 't';
09517 } else {
09518 switch (cmd) {
09519 case '1':
09520 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09521 break;
09522 case '2':
09523 DELETE(prefile, -1, prefile, vmu);
09524 ast_play_and_wait(chan, "vm-tempremoved");
09525 cmd = 't';
09526 break;
09527 case '*':
09528 cmd = 't';
09529 break;
09530 default:
09531 cmd = ast_play_and_wait(chan,
09532 ast_fileexists(prefile, NULL, NULL) > 0 ?
09533 "vm-tempgreeting2" : "vm-tempgreeting");
09534 if (!cmd) {
09535 cmd = ast_waitfordigit(chan, 6000);
09536 }
09537 if (!cmd) {
09538 retries++;
09539 }
09540 if (retries > 3) {
09541 cmd = 't';
09542 }
09543 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09544 }
09545 }
09546 DISPOSE(prefile, -1);
09547 }
09548 if (cmd == 't')
09549 cmd = 0;
09550 return cmd;
09551 }
09552
09553
09554
09555
09556
09557
09558
09559
09560
09561 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09562 {
09563 int cmd = 0;
09564
09565 if (vms->lastmsg > -1) {
09566 cmd = play_message(chan, vmu, vms);
09567 } else {
09568 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09569 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09570 if (!cmd) {
09571 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09572 cmd = ast_play_and_wait(chan, vms->fn);
09573 }
09574 if (!cmd)
09575 cmd = ast_play_and_wait(chan, "vm-messages");
09576 } else {
09577 if (!cmd)
09578 cmd = ast_play_and_wait(chan, "vm-messages");
09579 if (!cmd) {
09580 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09581 cmd = ast_play_and_wait(chan, vms->fn);
09582 }
09583 }
09584 }
09585 return cmd;
09586 }
09587
09588
09589 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09590 {
09591 int cmd = 0;
09592
09593 if (vms->lastmsg > -1) {
09594 cmd = play_message(chan, vmu, vms);
09595 } else {
09596 if (!strcasecmp(vms->fn, "INBOX")) {
09597 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09598 } else {
09599 cmd = ast_play_and_wait(chan, "vm-nomessages");
09600 }
09601 }
09602 return cmd;
09603 }
09604
09605
09606
09607
09608
09609
09610
09611
09612
09613 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09614 {
09615 int cmd = 0;
09616
09617 if (vms->lastmsg > -1) {
09618 cmd = play_message(chan, vmu, vms);
09619 } else {
09620 cmd = ast_play_and_wait(chan, "vm-youhave");
09621 if (!cmd)
09622 cmd = ast_play_and_wait(chan, "vm-no");
09623 if (!cmd) {
09624 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09625 cmd = ast_play_and_wait(chan, vms->fn);
09626 }
09627 if (!cmd)
09628 cmd = ast_play_and_wait(chan, "vm-messages");
09629 }
09630 return cmd;
09631 }
09632
09633
09634
09635
09636
09637
09638
09639
09640
09641 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09642 {
09643 int cmd;
09644
09645 if (vms->lastmsg > -1) {
09646 cmd = play_message(chan, vmu, vms);
09647 } else {
09648 cmd = ast_play_and_wait(chan, "vm-no");
09649 if (!cmd)
09650 cmd = ast_play_and_wait(chan, "vm-message");
09651 if (!cmd) {
09652 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09653 cmd = ast_play_and_wait(chan, vms->fn);
09654 }
09655 }
09656 return cmd;
09657 }
09658
09659
09660
09661
09662
09663
09664
09665
09666
09667 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09668 {
09669 int cmd;
09670
09671 if (vms->lastmsg > -1) {
09672 cmd = play_message(chan, vmu, vms);
09673 } else {
09674 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09675 if (!cmd)
09676 cmd = ast_play_and_wait(chan, "vm-messages");
09677 if (!cmd) {
09678 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09679 cmd = ast_play_and_wait(chan, vms->fn);
09680 }
09681 }
09682 return cmd;
09683 }
09684
09685
09686
09687
09688
09689
09690
09691
09692
09693 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09694 {
09695 int cmd;
09696
09697 if (vms->lastmsg > -1) {
09698 cmd = play_message(chan, vmu, vms);
09699 } else {
09700 cmd = ast_play_and_wait(chan, "vm-no");
09701 if (!cmd) {
09702 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09703 cmd = ast_play_and_wait(chan, vms->fn);
09704 }
09705 if (!cmd)
09706 cmd = ast_play_and_wait(chan, "vm-messages");
09707 }
09708 return cmd;
09709 }
09710
09711
09712
09713
09714
09715
09716
09717
09718
09719 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09720 {
09721 int cmd;
09722
09723 if (vms->lastmsg > -1) {
09724 cmd = play_message(chan, vmu, vms);
09725 } else {
09726 cmd = ast_play_and_wait(chan, "vm-you");
09727 if (!cmd)
09728 cmd = ast_play_and_wait(chan, "vm-haveno");
09729 if (!cmd)
09730 cmd = ast_play_and_wait(chan, "vm-messages");
09731 if (!cmd) {
09732 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09733 cmd = ast_play_and_wait(chan, vms->fn);
09734 }
09735 }
09736 return cmd;
09737 }
09738
09739
09740
09741
09742
09743
09744
09745
09746
09747 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09748 {
09749 int cmd = 0;
09750
09751 if (vms->lastmsg > -1) {
09752 cmd = play_message(chan, vmu, vms);
09753 } else {
09754 cmd = ast_play_and_wait(chan, "vm-no");
09755 if (!cmd) {
09756 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09757 cmd = ast_play_and_wait(chan, vms->fn);
09758 }
09759 }
09760 return cmd;
09761 }
09762
09763
09764
09765
09766
09767
09768
09769
09770
09771
09772
09773
09774 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09775 {
09776 if (!strncasecmp(chan->language, "es", 2)) {
09777 return vm_browse_messages_es(chan, vms, vmu);
09778 } else if (!strncasecmp(chan->language, "gr", 2)) {
09779 return vm_browse_messages_gr(chan, vms, vmu);
09780 } else if (!strncasecmp(chan->language, "he", 2)) {
09781 return vm_browse_messages_he(chan, vms, vmu);
09782 } else if (!strncasecmp(chan->language, "it", 2)) {
09783 return vm_browse_messages_it(chan, vms, vmu);
09784 } else if (!strncasecmp(chan->language, "pt", 2)) {
09785 return vm_browse_messages_pt(chan, vms, vmu);
09786 } else if (!strncasecmp(chan->language, "vi", 2)) {
09787 return vm_browse_messages_vi(chan, vms, vmu);
09788 } else if (!strncasecmp(chan->language, "zh", 2)) {
09789 return vm_browse_messages_zh(chan, vms, vmu);
09790 } else {
09791 return vm_browse_messages_en(chan, vms, vmu);
09792 }
09793 }
09794
09795 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09796 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09797 int skipuser, int max_logins, int silent)
09798 {
09799 int useadsi = 0, valid = 0, logretries = 0;
09800 char password[AST_MAX_EXTENSION]="", *passptr;
09801 struct ast_vm_user vmus, *vmu = NULL;
09802
09803
09804 adsi_begin(chan, &useadsi);
09805 if (!skipuser && useadsi)
09806 adsi_login(chan);
09807 ast_test_suite_event_notify("PLAYBACK", "Message: vm-login");
09808 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09809 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09810 return -1;
09811 }
09812
09813
09814
09815 while (!valid && (logretries < max_logins)) {
09816
09817 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09818 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09819 return -1;
09820 }
09821 if (ast_strlen_zero(mailbox)) {
09822 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09823 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09824 } else {
09825 ast_verb(3, "Username not entered\n");
09826 return -1;
09827 }
09828 } else if (mailbox[0] == '*') {
09829
09830 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09831 if (ast_exists_extension(chan, chan->context, "a", 1,
09832 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09833 return -1;
09834 }
09835 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09836 mailbox[0] = '\0';
09837 }
09838
09839 if (useadsi)
09840 adsi_password(chan);
09841
09842 if (!ast_strlen_zero(prefix)) {
09843 char fullusername[80] = "";
09844 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09845 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09846 ast_copy_string(mailbox, fullusername, mailbox_size);
09847 }
09848
09849 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09850 vmu = find_user(&vmus, context, mailbox);
09851 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09852
09853 password[0] = '\0';
09854 } else {
09855 ast_test_suite_event_notify("PLAYBACK", "Message: %s", vm_password);
09856 if (ast_streamfile(chan, vm_password, chan->language)) {
09857 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09858 return -1;
09859 }
09860 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09861 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09862 return -1;
09863 } else if (password[0] == '*') {
09864
09865 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
09866 if (ast_exists_extension(chan, chan->context, "a", 1,
09867 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09868 mailbox[0] = '*';
09869 return -1;
09870 }
09871 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09872 mailbox[0] = '\0';
09873
09874 vmu = NULL;
09875 }
09876 }
09877
09878 if (vmu) {
09879 passptr = vmu->password;
09880 if (passptr[0] == '-') passptr++;
09881 }
09882 if (vmu && !strcmp(passptr, password))
09883 valid++;
09884 else {
09885 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09886 if (!ast_strlen_zero(prefix))
09887 mailbox[0] = '\0';
09888 }
09889 logretries++;
09890 if (!valid) {
09891 if (skipuser || logretries >= max_logins) {
09892 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect");
09893 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09894 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09895 return -1;
09896 }
09897 } else {
09898 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect-mailbox");
09899 if (useadsi)
09900 adsi_login(chan);
09901 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09902 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09903 return -1;
09904 }
09905 }
09906 if (ast_waitstream(chan, ""))
09907 return -1;
09908 }
09909 }
09910 if (!valid && (logretries >= max_logins)) {
09911 ast_stopstream(chan);
09912 ast_play_and_wait(chan, "vm-goodbye");
09913 return -1;
09914 }
09915 if (vmu && !skipuser) {
09916 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09917 }
09918 return 0;
09919 }
09920
09921 static int vm_execmain(struct ast_channel *chan, const char *data)
09922 {
09923
09924
09925
09926 int res = -1;
09927 int cmd = 0;
09928 int valid = 0;
09929 char prefixstr[80] ="";
09930 char ext_context[256]="";
09931 int box;
09932 int useadsi = 0;
09933 int skipuser = 0;
09934 struct vm_state vms;
09935 struct ast_vm_user *vmu = NULL, vmus;
09936 char *context = NULL;
09937 int silentexit = 0;
09938 struct ast_flags flags = { 0 };
09939 signed char record_gain = 0;
09940 int play_auto = 0;
09941 int play_folder = 0;
09942 int in_urgent = 0;
09943 #ifdef IMAP_STORAGE
09944 int deleted = 0;
09945 #endif
09946
09947
09948 memset(&vms, 0, sizeof(vms));
09949
09950 vms.lastmsg = -1;
09951
09952 memset(&vmus, 0, sizeof(vmus));
09953
09954 ast_test_suite_event_notify("START", "Message: vm_execmain started");
09955 if (chan->_state != AST_STATE_UP) {
09956 ast_debug(1, "Before ast_answer\n");
09957 ast_answer(chan);
09958 }
09959
09960 if (!ast_strlen_zero(data)) {
09961 char *opts[OPT_ARG_ARRAY_SIZE];
09962 char *parse;
09963 AST_DECLARE_APP_ARGS(args,
09964 AST_APP_ARG(argv0);
09965 AST_APP_ARG(argv1);
09966 );
09967
09968 parse = ast_strdupa(data);
09969
09970 AST_STANDARD_APP_ARGS(args, parse);
09971
09972 if (args.argc == 2) {
09973 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09974 return -1;
09975 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09976 int gain;
09977 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09978 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09979 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09980 return -1;
09981 } else {
09982 record_gain = (signed char) gain;
09983 }
09984 } else {
09985 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09986 }
09987 }
09988 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
09989 play_auto = 1;
09990 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
09991
09992 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
09993 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
09994 play_folder = -1;
09995 }
09996 } else {
09997 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
09998 }
09999 } else {
10000 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
10001 }
10002 if (play_folder > 9 || play_folder < 0) {
10003 ast_log(AST_LOG_WARNING,
10004 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
10005 opts[OPT_ARG_PLAYFOLDER]);
10006 play_folder = 0;
10007 }
10008 }
10009 } else {
10010
10011 while (*(args.argv0)) {
10012 if (*(args.argv0) == 's')
10013 ast_set_flag(&flags, OPT_SILENT);
10014 else if (*(args.argv0) == 'p')
10015 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
10016 else
10017 break;
10018 (args.argv0)++;
10019 }
10020
10021 }
10022
10023 valid = ast_test_flag(&flags, OPT_SILENT);
10024
10025 if ((context = strchr(args.argv0, '@')))
10026 *context++ = '\0';
10027
10028 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
10029 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
10030 else
10031 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
10032
10033 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
10034 skipuser++;
10035 else
10036 valid = 0;
10037 }
10038
10039 if (!valid)
10040 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
10041
10042 ast_debug(1, "After vm_authenticate\n");
10043
10044 if (vms.username[0] == '*') {
10045 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
10046
10047
10048 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
10049 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
10050 res = 0;
10051 goto out;
10052 }
10053 }
10054
10055 if (!res) {
10056 valid = 1;
10057 if (!skipuser)
10058 vmu = &vmus;
10059 } else {
10060 res = 0;
10061 }
10062
10063
10064 adsi_begin(chan, &useadsi);
10065
10066 ast_test_suite_assert(valid);
10067 if (!valid) {
10068 goto out;
10069 }
10070 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
10071
10072 #ifdef IMAP_STORAGE
10073 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10074 pthread_setspecific(ts_vmstate.key, &vms);
10075
10076 vms.interactive = 1;
10077 vms.updated = 1;
10078 if (vmu)
10079 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10080 vmstate_insert(&vms);
10081 init_vm_state(&vms);
10082 #endif
10083
10084
10085 if (!ast_strlen_zero(vmu->language))
10086 ast_string_field_set(chan, language, vmu->language);
10087
10088
10089 ast_debug(1, "Before open_mailbox\n");
10090 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10091 if (res < 0)
10092 goto out;
10093 vms.oldmessages = vms.lastmsg + 1;
10094 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10095
10096 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10097 if (res < 0)
10098 goto out;
10099 vms.newmessages = vms.lastmsg + 1;
10100 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10101
10102 in_urgent = 1;
10103 res = open_mailbox(&vms, vmu, 11);
10104 if (res < 0)
10105 goto out;
10106 vms.urgentmessages = vms.lastmsg + 1;
10107 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10108
10109
10110 if (play_auto) {
10111 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10112 if (vms.urgentmessages) {
10113 in_urgent = 1;
10114 res = open_mailbox(&vms, vmu, 11);
10115 } else {
10116 in_urgent = 0;
10117 res = open_mailbox(&vms, vmu, play_folder);
10118 }
10119 if (res < 0)
10120 goto out;
10121
10122
10123 if (vms.lastmsg == -1) {
10124 in_urgent = 0;
10125 cmd = vm_browse_messages(chan, &vms, vmu);
10126 res = 0;
10127 goto out;
10128 }
10129 } else {
10130 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10131
10132 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10133 in_urgent = 0;
10134 play_folder = 1;
10135 if (res < 0)
10136 goto out;
10137 } else if (!vms.urgentmessages && vms.newmessages) {
10138
10139 in_urgent = 0;
10140 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10141 if (res < 0)
10142 goto out;
10143 }
10144 }
10145
10146 if (useadsi)
10147 adsi_status(chan, &vms);
10148 res = 0;
10149
10150
10151 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10152 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10153 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10154 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10155 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10156 if ((cmd == 't') || (cmd == '#')) {
10157
10158 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10159 res = 0;
10160 goto out;
10161 } else if (cmd < 0) {
10162
10163 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10164 res = -1;
10165 goto out;
10166 }
10167 }
10168 #ifdef IMAP_STORAGE
10169 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10170 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10171 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10172 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10173 }
10174 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10175 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10176 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10177 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10178 }
10179 #endif
10180
10181 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10182 if (play_auto) {
10183 cmd = '1';
10184 } else {
10185 cmd = vm_intro(chan, vmu, &vms);
10186 }
10187 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10188
10189 vms.repeats = 0;
10190 vms.starting = 1;
10191 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10192
10193 switch (cmd) {
10194 case '1':
10195 vms.curmsg = 0;
10196
10197 case '5':
10198 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10199 cmd = vm_browse_messages(chan, &vms, vmu);
10200 break;
10201 case '2':
10202 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10203 if (useadsi)
10204 adsi_folders(chan, 0, "Change to folder...");
10205
10206 cmd = get_folder2(chan, "vm-changeto", 0);
10207 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10208 if (cmd == '#') {
10209 cmd = 0;
10210 } else if (cmd > 0) {
10211 cmd = cmd - '0';
10212 res = close_mailbox(&vms, vmu);
10213 if (res == ERROR_LOCK_PATH)
10214 goto out;
10215
10216 if (cmd != 11) in_urgent = 0;
10217 res = open_mailbox(&vms, vmu, cmd);
10218 if (res < 0)
10219 goto out;
10220 play_folder = cmd;
10221 cmd = 0;
10222 }
10223 if (useadsi)
10224 adsi_status2(chan, &vms);
10225
10226 if (!cmd) {
10227 cmd = vm_play_folder_name(chan, vms.vmbox);
10228 }
10229
10230 vms.starting = 1;
10231 vms.curmsg = 0;
10232 break;
10233 case '3':
10234 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10235 cmd = 0;
10236 vms.repeats = 0;
10237 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10238 switch (cmd) {
10239 case '1':
10240 if (vms.lastmsg > -1 && !vms.starting) {
10241 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10242 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10243 res = cmd;
10244 goto out;
10245 }
10246 } else {
10247 cmd = ast_play_and_wait(chan, "vm-sorry");
10248 }
10249 cmd = 't';
10250 break;
10251 case '2':
10252 if (!vms.starting)
10253 ast_verb(3, "Callback Requested\n");
10254 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10255 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10256 if (cmd == 9) {
10257 silentexit = 1;
10258 goto out;
10259 } else if (cmd == ERROR_LOCK_PATH) {
10260 res = cmd;
10261 goto out;
10262 }
10263 } else {
10264 cmd = ast_play_and_wait(chan, "vm-sorry");
10265 }
10266 cmd = 't';
10267 break;
10268 case '3':
10269 if (vms.lastmsg > -1 && !vms.starting) {
10270 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10271 if (cmd == ERROR_LOCK_PATH) {
10272 res = cmd;
10273 goto out;
10274 }
10275 } else {
10276 cmd = ast_play_and_wait(chan, "vm-sorry");
10277 }
10278 cmd = 't';
10279 break;
10280 case '4':
10281 if (!ast_strlen_zero(vmu->dialout)) {
10282 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10283 if (cmd == 9) {
10284 silentexit = 1;
10285 goto out;
10286 }
10287 } else {
10288 cmd = ast_play_and_wait(chan, "vm-sorry");
10289 }
10290 cmd = 't';
10291 break;
10292
10293 case '5':
10294 if (ast_test_flag(vmu, VM_SVMAIL)) {
10295 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10296 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10297 res = cmd;
10298 goto out;
10299 }
10300 } else {
10301 cmd = ast_play_and_wait(chan, "vm-sorry");
10302 }
10303 cmd = 't';
10304 break;
10305
10306 case '*':
10307 cmd = 't';
10308 break;
10309
10310 default:
10311 cmd = 0;
10312 if (!vms.starting) {
10313 cmd = ast_play_and_wait(chan, "vm-toreply");
10314 }
10315 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10316 cmd = ast_play_and_wait(chan, "vm-tocallback");
10317 }
10318 if (!cmd && !vms.starting) {
10319 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10320 }
10321 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10322 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10323 }
10324 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10325 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10326 }
10327 if (!cmd) {
10328 cmd = ast_play_and_wait(chan, "vm-starmain");
10329 }
10330 if (!cmd) {
10331 cmd = ast_waitfordigit(chan, 6000);
10332 }
10333 if (!cmd) {
10334 vms.repeats++;
10335 }
10336 if (vms.repeats > 3) {
10337 cmd = 't';
10338 }
10339 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10340 }
10341 }
10342 if (cmd == 't') {
10343 cmd = 0;
10344 vms.repeats = 0;
10345 }
10346 break;
10347 case '4':
10348 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10349 if (vms.curmsg > 0) {
10350 vms.curmsg--;
10351 cmd = play_message(chan, vmu, &vms);
10352 } else {
10353
10354
10355
10356
10357 if (in_urgent == 0 && vms.urgentmessages > 0) {
10358
10359 in_urgent = 1;
10360 res = close_mailbox(&vms, vmu);
10361 if (res == ERROR_LOCK_PATH)
10362 goto out;
10363 res = open_mailbox(&vms, vmu, 11);
10364 if (res < 0)
10365 goto out;
10366 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10367 vms.curmsg = vms.lastmsg;
10368 if (vms.lastmsg < 0) {
10369 cmd = ast_play_and_wait(chan, "vm-nomore");
10370 }
10371 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10372 vms.curmsg = vms.lastmsg;
10373 cmd = play_message(chan, vmu, &vms);
10374 } else {
10375 cmd = ast_play_and_wait(chan, "vm-nomore");
10376 }
10377 }
10378 break;
10379 case '6':
10380 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10381 if (vms.curmsg < vms.lastmsg) {
10382 vms.curmsg++;
10383 cmd = play_message(chan, vmu, &vms);
10384 } else {
10385 if (in_urgent && vms.newmessages > 0) {
10386
10387
10388
10389
10390 in_urgent = 0;
10391 res = close_mailbox(&vms, vmu);
10392 if (res == ERROR_LOCK_PATH)
10393 goto out;
10394 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10395 if (res < 0)
10396 goto out;
10397 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10398 vms.curmsg = -1;
10399 if (vms.lastmsg < 0) {
10400 cmd = ast_play_and_wait(chan, "vm-nomore");
10401 }
10402 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10403 vms.curmsg = 0;
10404 cmd = play_message(chan, vmu, &vms);
10405 } else {
10406 cmd = ast_play_and_wait(chan, "vm-nomore");
10407 }
10408 }
10409 break;
10410 case '7':
10411 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10412 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10413 if (useadsi)
10414 adsi_delete(chan, &vms);
10415 if (vms.deleted[vms.curmsg]) {
10416 if (play_folder == 0) {
10417 if (in_urgent) {
10418 vms.urgentmessages--;
10419 } else {
10420 vms.newmessages--;
10421 }
10422 }
10423 else if (play_folder == 1)
10424 vms.oldmessages--;
10425 cmd = ast_play_and_wait(chan, "vm-deleted");
10426 } else {
10427 if (play_folder == 0) {
10428 if (in_urgent) {
10429 vms.urgentmessages++;
10430 } else {
10431 vms.newmessages++;
10432 }
10433 }
10434 else if (play_folder == 1)
10435 vms.oldmessages++;
10436 cmd = ast_play_and_wait(chan, "vm-undeleted");
10437 }
10438 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10439 if (vms.curmsg < vms.lastmsg) {
10440 vms.curmsg++;
10441 cmd = play_message(chan, vmu, &vms);
10442 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10443 vms.curmsg = 0;
10444 cmd = play_message(chan, vmu, &vms);
10445 } else {
10446
10447
10448
10449
10450 if (in_urgent == 1) {
10451
10452 in_urgent = 0;
10453 res = close_mailbox(&vms, vmu);
10454 if (res == ERROR_LOCK_PATH)
10455 goto out;
10456 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10457 if (res < 0)
10458 goto out;
10459 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10460 vms.curmsg = -1;
10461 if (vms.lastmsg < 0) {
10462 cmd = ast_play_and_wait(chan, "vm-nomore");
10463 }
10464 } else {
10465 cmd = ast_play_and_wait(chan, "vm-nomore");
10466 }
10467 }
10468 }
10469 } else
10470 cmd = 0;
10471 #ifdef IMAP_STORAGE
10472 deleted = 1;
10473 #endif
10474 break;
10475
10476 case '8':
10477 if (vms.lastmsg > -1) {
10478 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10479 if (cmd == ERROR_LOCK_PATH) {
10480 res = cmd;
10481 goto out;
10482 }
10483 } else {
10484
10485
10486
10487
10488 if (in_urgent == 1 && vms.newmessages > 0) {
10489
10490 in_urgent = 0;
10491 res = close_mailbox(&vms, vmu);
10492 if (res == ERROR_LOCK_PATH)
10493 goto out;
10494 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10495 if (res < 0)
10496 goto out;
10497 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10498 vms.curmsg = -1;
10499 if (vms.lastmsg < 0) {
10500 cmd = ast_play_and_wait(chan, "vm-nomore");
10501 }
10502 } else {
10503 cmd = ast_play_and_wait(chan, "vm-nomore");
10504 }
10505 }
10506 break;
10507 case '9':
10508 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10509 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10510
10511 cmd = 0;
10512 break;
10513 }
10514 if (useadsi)
10515 adsi_folders(chan, 1, "Save to folder...");
10516 cmd = get_folder2(chan, "vm-savefolder", 1);
10517 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10518 box = 0;
10519 if (cmd == '#') {
10520 cmd = 0;
10521 break;
10522 } else if (cmd > 0) {
10523 box = cmd = cmd - '0';
10524 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10525 if (cmd == ERROR_LOCK_PATH) {
10526 res = cmd;
10527 goto out;
10528 #ifndef IMAP_STORAGE
10529 } else if (!cmd) {
10530 vms.deleted[vms.curmsg] = 1;
10531 #endif
10532 } else {
10533 vms.deleted[vms.curmsg] = 0;
10534 vms.heard[vms.curmsg] = 0;
10535 }
10536 }
10537 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10538 if (useadsi)
10539 adsi_message(chan, &vms);
10540 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10541 if (!cmd) {
10542 cmd = ast_play_and_wait(chan, "vm-message");
10543 if (!cmd)
10544 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10545 if (!cmd)
10546 cmd = ast_play_and_wait(chan, "vm-savedto");
10547 if (!cmd)
10548 cmd = vm_play_folder_name(chan, vms.fn);
10549 } else {
10550 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10551 }
10552 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10553 if (vms.curmsg < vms.lastmsg) {
10554 vms.curmsg++;
10555 cmd = play_message(chan, vmu, &vms);
10556 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10557 vms.curmsg = 0;
10558 cmd = play_message(chan, vmu, &vms);
10559 } else {
10560
10561
10562
10563
10564 if (in_urgent == 1 && vms.newmessages > 0) {
10565
10566 in_urgent = 0;
10567 res = close_mailbox(&vms, vmu);
10568 if (res == ERROR_LOCK_PATH)
10569 goto out;
10570 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10571 if (res < 0)
10572 goto out;
10573 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10574 vms.curmsg = -1;
10575 if (vms.lastmsg < 0) {
10576 cmd = ast_play_and_wait(chan, "vm-nomore");
10577 }
10578 } else {
10579 cmd = ast_play_and_wait(chan, "vm-nomore");
10580 }
10581 }
10582 }
10583 break;
10584 case '*':
10585 if (!vms.starting) {
10586 cmd = ast_play_and_wait(chan, "vm-onefor");
10587 if (!strncasecmp(chan->language, "he", 2)) {
10588 cmd = ast_play_and_wait(chan, "vm-for");
10589 }
10590 if (!cmd)
10591 cmd = vm_play_folder_name(chan, vms.vmbox);
10592 if (!cmd)
10593 cmd = ast_play_and_wait(chan, "vm-opts");
10594 if (!cmd)
10595 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10596 } else
10597 cmd = 0;
10598 break;
10599 case '0':
10600 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10601 if (useadsi)
10602 adsi_status(chan, &vms);
10603 break;
10604 default:
10605 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10606 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10607 break;
10608 }
10609 }
10610 if ((cmd == 't') || (cmd == '#')) {
10611
10612 res = 0;
10613 } else {
10614
10615 res = -1;
10616 }
10617
10618 out:
10619 if (res > -1) {
10620 ast_stopstream(chan);
10621 adsi_goodbye(chan);
10622 if (valid && res != OPERATOR_EXIT) {
10623 if (silentexit)
10624 res = ast_play_and_wait(chan, "vm-dialout");
10625 else
10626 res = ast_play_and_wait(chan, "vm-goodbye");
10627 }
10628 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10629 res = 0;
10630 }
10631 if (useadsi)
10632 ast_adsi_unload_session(chan);
10633 }
10634 if (vmu)
10635 close_mailbox(&vms, vmu);
10636 if (valid) {
10637 int new = 0, old = 0, urgent = 0;
10638 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10639 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10640
10641 run_externnotify(vmu->context, vmu->mailbox, NULL);
10642 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10643 queue_mwi_event(ext_context, urgent, new, old);
10644 }
10645 #ifdef IMAP_STORAGE
10646
10647 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10648 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10649 ast_mutex_lock(&vms.lock);
10650 #ifdef HAVE_IMAP_TK2006
10651 if (LEVELUIDPLUS (vms.mailstream)) {
10652 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10653 } else
10654 #endif
10655 mail_expunge(vms.mailstream);
10656 ast_mutex_unlock(&vms.lock);
10657 }
10658
10659
10660 if (vmu) {
10661 vmstate_delete(&vms);
10662 }
10663 #endif
10664 if (vmu)
10665 free_user(vmu);
10666
10667 #ifdef IMAP_STORAGE
10668 pthread_setspecific(ts_vmstate.key, NULL);
10669 #endif
10670 return res;
10671 }
10672
10673 static int vm_exec(struct ast_channel *chan, const char *data)
10674 {
10675 int res = 0;
10676 char *tmp;
10677 struct leave_vm_options leave_options;
10678 struct ast_flags flags = { 0 };
10679 char *opts[OPT_ARG_ARRAY_SIZE];
10680 AST_DECLARE_APP_ARGS(args,
10681 AST_APP_ARG(argv0);
10682 AST_APP_ARG(argv1);
10683 );
10684
10685 memset(&leave_options, 0, sizeof(leave_options));
10686
10687 if (chan->_state != AST_STATE_UP)
10688 ast_answer(chan);
10689
10690 if (!ast_strlen_zero(data)) {
10691 tmp = ast_strdupa(data);
10692 AST_STANDARD_APP_ARGS(args, tmp);
10693 if (args.argc == 2) {
10694 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10695 return -1;
10696 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10697 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10698 int gain;
10699
10700 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10701 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10702 return -1;
10703 } else {
10704 leave_options.record_gain = (signed char) gain;
10705 }
10706 }
10707 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10708 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10709 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10710 }
10711 }
10712 } else {
10713 char temp[256];
10714 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10715 if (res < 0)
10716 return res;
10717 if (ast_strlen_zero(temp))
10718 return 0;
10719 args.argv0 = ast_strdupa(temp);
10720 }
10721
10722 res = leave_voicemail(chan, args.argv0, &leave_options);
10723 if (res == 't') {
10724 ast_play_and_wait(chan, "vm-goodbye");
10725 res = 0;
10726 }
10727
10728 if (res == OPERATOR_EXIT) {
10729 res = 0;
10730 }
10731
10732 if (res == ERROR_LOCK_PATH) {
10733 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10734 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10735 res = 0;
10736 }
10737
10738 return res;
10739 }
10740
10741 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10742 {
10743 struct ast_vm_user *vmu;
10744
10745 if (!ast_strlen_zero(box) && box[0] == '*') {
10746 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10747 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10748 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10749 "\n\tand will be ignored.\n", box, context);
10750 return NULL;
10751 }
10752
10753 AST_LIST_TRAVERSE(&users, vmu, list) {
10754 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10755 if (strcasecmp(vmu->context, context)) {
10756 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10757 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10758 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10759 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10760 }
10761 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10762 return NULL;
10763 }
10764 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10765 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10766 return NULL;
10767 }
10768 }
10769
10770 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10771 return NULL;
10772
10773 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10774 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10775
10776 AST_LIST_INSERT_TAIL(&users, vmu, list);
10777
10778 return vmu;
10779 }
10780
10781 static int append_mailbox(const char *context, const char *box, const char *data)
10782 {
10783
10784 char *tmp;
10785 char *stringp;
10786 char *s;
10787 struct ast_vm_user *vmu;
10788 char *mailbox_full;
10789 int new = 0, old = 0, urgent = 0;
10790 char secretfn[PATH_MAX] = "";
10791
10792 tmp = ast_strdupa(data);
10793
10794 if (!(vmu = find_or_create(context, box)))
10795 return -1;
10796
10797 populate_defaults(vmu);
10798
10799 stringp = tmp;
10800 if ((s = strsep(&stringp, ","))) {
10801 if (!ast_strlen_zero(s) && s[0] == '*') {
10802 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10803 "\n\tmust be reset in voicemail.conf.\n", box);
10804 }
10805
10806 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10807 }
10808 if (stringp && (s = strsep(&stringp, ","))) {
10809 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10810 }
10811 if (stringp && (s = strsep(&stringp, ","))) {
10812 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10813 }
10814 if (stringp && (s = strsep(&stringp, ","))) {
10815 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10816 }
10817 if (stringp && (s = strsep(&stringp, ","))) {
10818 apply_options(vmu, s);
10819 }
10820
10821 switch (vmu->passwordlocation) {
10822 case OPT_PWLOC_SPOOLDIR:
10823 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10824 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10825 }
10826
10827 mailbox_full = ast_alloca(strlen(box) + strlen(context) + 1);
10828 strcpy(mailbox_full, box);
10829 strcat(mailbox_full, "@");
10830 strcat(mailbox_full, context);
10831
10832 inboxcount2(mailbox_full, &urgent, &new, &old);
10833 queue_mwi_event(mailbox_full, urgent, new, old);
10834
10835 return 0;
10836 }
10837
10838 AST_TEST_DEFINE(test_voicemail_vmuser)
10839 {
10840 int res = 0;
10841 struct ast_vm_user *vmu;
10842
10843 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10844 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10845 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10846 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10847 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10848 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10849 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10850 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10851 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10852 #ifdef IMAP_STORAGE
10853 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10854 "imapfolder=INBOX|imapvmshareid=6000";
10855 #endif
10856
10857 switch (cmd) {
10858 case TEST_INIT:
10859 info->name = "vmuser";
10860 info->category = "/apps/app_voicemail/";
10861 info->summary = "Vmuser unit test";
10862 info->description =
10863 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10864 return AST_TEST_NOT_RUN;
10865 case TEST_EXECUTE:
10866 break;
10867 }
10868
10869 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10870 return AST_TEST_NOT_RUN;
10871 }
10872 populate_defaults(vmu);
10873 ast_set_flag(vmu, VM_ALLOCED);
10874
10875 apply_options(vmu, options_string);
10876
10877 if (!ast_test_flag(vmu, VM_ATTACH)) {
10878 ast_test_status_update(test, "Parse failure for attach option\n");
10879 res = 1;
10880 }
10881 if (strcasecmp(vmu->attachfmt, "wav49")) {
10882 ast_test_status_update(test, "Parse failure for attachftm option\n");
10883 res = 1;
10884 }
10885 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10886 ast_test_status_update(test, "Parse failure for serveremail option\n");
10887 res = 1;
10888 }
10889 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10890 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10891 res = 1;
10892 }
10893 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10894 ast_test_status_update(test, "Parse failure for emailbody option\n");
10895 res = 1;
10896 }
10897 if (strcasecmp(vmu->zonetag, "central")) {
10898 ast_test_status_update(test, "Parse failure for tz option\n");
10899 res = 1;
10900 }
10901 if (!ast_test_flag(vmu, VM_DELETE)) {
10902 ast_test_status_update(test, "Parse failure for delete option\n");
10903 res = 1;
10904 }
10905 if (!ast_test_flag(vmu, VM_SAYCID)) {
10906 ast_test_status_update(test, "Parse failure for saycid option\n");
10907 res = 1;
10908 }
10909 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10910 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10911 res = 1;
10912 }
10913 if (!ast_test_flag(vmu, VM_REVIEW)) {
10914 ast_test_status_update(test, "Parse failure for review option\n");
10915 res = 1;
10916 }
10917 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10918 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10919 res = 1;
10920 }
10921 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10922 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10923 res = 1;
10924 }
10925 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10926 ast_test_status_update(test, "Parse failure for operator option\n");
10927 res = 1;
10928 }
10929 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10930 ast_test_status_update(test, "Parse failure for envelope option\n");
10931 res = 1;
10932 }
10933 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10934 ast_test_status_update(test, "Parse failure for moveheard option\n");
10935 res = 1;
10936 }
10937 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10938 ast_test_status_update(test, "Parse failure for sayduration option\n");
10939 res = 1;
10940 }
10941 if (vmu->saydurationm != 5) {
10942 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10943 res = 1;
10944 }
10945 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10946 ast_test_status_update(test, "Parse failure for forcename option\n");
10947 res = 1;
10948 }
10949 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10950 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10951 res = 1;
10952 }
10953 if (strcasecmp(vmu->callback, "somecontext")) {
10954 ast_test_status_update(test, "Parse failure for callbacks option\n");
10955 res = 1;
10956 }
10957 if (strcasecmp(vmu->dialout, "somecontext2")) {
10958 ast_test_status_update(test, "Parse failure for dialout option\n");
10959 res = 1;
10960 }
10961 if (strcasecmp(vmu->exit, "somecontext3")) {
10962 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10963 res = 1;
10964 }
10965 if (vmu->minsecs != 10) {
10966 ast_test_status_update(test, "Parse failure for minsecs option\n");
10967 res = 1;
10968 }
10969 if (vmu->maxsecs != 100) {
10970 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10971 res = 1;
10972 }
10973 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10974 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10975 res = 1;
10976 }
10977 if (vmu->maxdeletedmsg != 50) {
10978 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10979 res = 1;
10980 }
10981 if (vmu->volgain != 1.3) {
10982 ast_test_status_update(test, "Parse failure for volgain option\n");
10983 res = 1;
10984 }
10985 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10986 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10987 res = 1;
10988 }
10989 #ifdef IMAP_STORAGE
10990 apply_options(vmu, option_string2);
10991
10992 if (strcasecmp(vmu->imapuser, "imapuser")) {
10993 ast_test_status_update(test, "Parse failure for imapuser option\n");
10994 res = 1;
10995 }
10996 if (strcasecmp(vmu->imappassword, "imappasswd")) {
10997 ast_test_status_update(test, "Parse failure for imappasswd option\n");
10998 res = 1;
10999 }
11000 if (strcasecmp(vmu->imapfolder, "INBOX")) {
11001 ast_test_status_update(test, "Parse failure for imapfolder option\n");
11002 res = 1;
11003 }
11004 if (strcasecmp(vmu->imapvmshareid, "6000")) {
11005 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
11006 res = 1;
11007 }
11008 #endif
11009
11010 free_user(vmu);
11011 return res ? AST_TEST_FAIL : AST_TEST_PASS;
11012 }
11013
11014 static int vm_box_exists(struct ast_channel *chan, const char *data)
11015 {
11016 struct ast_vm_user svm;
11017 char *context, *box;
11018 AST_DECLARE_APP_ARGS(args,
11019 AST_APP_ARG(mbox);
11020 AST_APP_ARG(options);
11021 );
11022 static int dep_warning = 0;
11023
11024 if (ast_strlen_zero(data)) {
11025 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
11026 return -1;
11027 }
11028
11029 if (!dep_warning) {
11030 dep_warning = 1;
11031 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
11032 }
11033
11034 box = ast_strdupa(data);
11035
11036 AST_STANDARD_APP_ARGS(args, box);
11037
11038 if (args.options) {
11039 }
11040
11041 if ((context = strchr(args.mbox, '@'))) {
11042 *context = '\0';
11043 context++;
11044 }
11045
11046 if (find_user(&svm, context, args.mbox)) {
11047 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
11048 } else
11049 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
11050
11051 return 0;
11052 }
11053
11054 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
11055 {
11056 struct ast_vm_user svm;
11057 AST_DECLARE_APP_ARGS(arg,
11058 AST_APP_ARG(mbox);
11059 AST_APP_ARG(context);
11060 );
11061
11062 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
11063
11064 if (ast_strlen_zero(arg.mbox)) {
11065 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11066 return -1;
11067 }
11068
11069 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
11070 return 0;
11071 }
11072
11073 static struct ast_custom_function mailbox_exists_acf = {
11074 .name = "MAILBOX_EXISTS",
11075 .read = acf_mailbox_exists,
11076 };
11077
11078 static int vmauthenticate(struct ast_channel *chan, const char *data)
11079 {
11080 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11081 struct ast_vm_user vmus;
11082 char *options = NULL;
11083 int silent = 0, skipuser = 0;
11084 int res = -1;
11085
11086 if (data) {
11087 s = ast_strdupa(data);
11088 user = strsep(&s, ",");
11089 options = strsep(&s, ",");
11090 if (user) {
11091 s = user;
11092 user = strsep(&s, "@");
11093 context = strsep(&s, "");
11094 if (!ast_strlen_zero(user))
11095 skipuser++;
11096 ast_copy_string(mailbox, user, sizeof(mailbox));
11097 }
11098 }
11099
11100 if (options) {
11101 silent = (strchr(options, 's')) != NULL;
11102 }
11103
11104 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11105 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11106 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11107 ast_play_and_wait(chan, "auth-thankyou");
11108 res = 0;
11109 } else if (mailbox[0] == '*') {
11110
11111 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11112 res = 0;
11113 }
11114 }
11115
11116 return res;
11117 }
11118
11119 static char *show_users_realtime(int fd, const char *context)
11120 {
11121 struct ast_config *cfg;
11122 const char *cat = NULL;
11123
11124 if (!(cfg = ast_load_realtime_multientry("voicemail",
11125 "context", context, SENTINEL))) {
11126 return CLI_FAILURE;
11127 }
11128
11129 ast_cli(fd,
11130 "\n"
11131 "=============================================================\n"
11132 "=== Configured Voicemail Users ==============================\n"
11133 "=============================================================\n"
11134 "===\n");
11135
11136 while ((cat = ast_category_browse(cfg, cat))) {
11137 struct ast_variable *var = NULL;
11138 ast_cli(fd,
11139 "=== Mailbox ...\n"
11140 "===\n");
11141 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11142 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11143 ast_cli(fd,
11144 "===\n"
11145 "=== ---------------------------------------------------------\n"
11146 "===\n");
11147 }
11148
11149 ast_cli(fd,
11150 "=============================================================\n"
11151 "\n");
11152
11153 ast_config_destroy(cfg);
11154
11155 return CLI_SUCCESS;
11156 }
11157
11158 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11159 {
11160 int which = 0;
11161 int wordlen;
11162 struct ast_vm_user *vmu;
11163 const char *context = "";
11164
11165
11166 if (pos > 4)
11167 return NULL;
11168 if (pos == 3)
11169 return (state == 0) ? ast_strdup("for") : NULL;
11170 wordlen = strlen(word);
11171 AST_LIST_TRAVERSE(&users, vmu, list) {
11172 if (!strncasecmp(word, vmu->context, wordlen)) {
11173 if (context && strcmp(context, vmu->context) && ++which > state)
11174 return ast_strdup(vmu->context);
11175
11176 context = vmu->context;
11177 }
11178 }
11179 return NULL;
11180 }
11181
11182
11183 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11184 {
11185 struct ast_vm_user *vmu;
11186 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11187 const char *context = NULL;
11188 int users_counter = 0;
11189
11190 switch (cmd) {
11191 case CLI_INIT:
11192 e->command = "voicemail show users";
11193 e->usage =
11194 "Usage: voicemail show users [for <context>]\n"
11195 " Lists all mailboxes currently set up\n";
11196 return NULL;
11197 case CLI_GENERATE:
11198 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11199 }
11200
11201 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11202 return CLI_SHOWUSAGE;
11203 if (a->argc == 5) {
11204 if (strcmp(a->argv[3],"for"))
11205 return CLI_SHOWUSAGE;
11206 context = a->argv[4];
11207 }
11208
11209 if (ast_check_realtime("voicemail")) {
11210 if (!context) {
11211 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11212 return CLI_SHOWUSAGE;
11213 }
11214 return show_users_realtime(a->fd, context);
11215 }
11216
11217 AST_LIST_LOCK(&users);
11218 if (AST_LIST_EMPTY(&users)) {
11219 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11220 AST_LIST_UNLOCK(&users);
11221 return CLI_FAILURE;
11222 }
11223 if (!context) {
11224 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11225 } else {
11226 int count = 0;
11227 AST_LIST_TRAVERSE(&users, vmu, list) {
11228 if (!strcmp(context, vmu->context)) {
11229 count++;
11230 break;
11231 }
11232 }
11233 if (count) {
11234 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11235 } else {
11236 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11237 AST_LIST_UNLOCK(&users);
11238 return CLI_FAILURE;
11239 }
11240 }
11241 AST_LIST_TRAVERSE(&users, vmu, list) {
11242 int newmsgs = 0, oldmsgs = 0;
11243 char count[12], tmp[256] = "";
11244
11245 if (!context || !strcmp(context, vmu->context)) {
11246 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11247 inboxcount(tmp, &newmsgs, &oldmsgs);
11248 snprintf(count, sizeof(count), "%d", newmsgs);
11249 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11250 users_counter++;
11251 }
11252 }
11253 AST_LIST_UNLOCK(&users);
11254 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11255 return CLI_SUCCESS;
11256 }
11257
11258
11259 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11260 {
11261 struct vm_zone *zone;
11262 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11263 char *res = CLI_SUCCESS;
11264
11265 switch (cmd) {
11266 case CLI_INIT:
11267 e->command = "voicemail show zones";
11268 e->usage =
11269 "Usage: voicemail show zones\n"
11270 " Lists zone message formats\n";
11271 return NULL;
11272 case CLI_GENERATE:
11273 return NULL;
11274 }
11275
11276 if (a->argc != 3)
11277 return CLI_SHOWUSAGE;
11278
11279 AST_LIST_LOCK(&zones);
11280 if (!AST_LIST_EMPTY(&zones)) {
11281 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11282 AST_LIST_TRAVERSE(&zones, zone, list) {
11283 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11284 }
11285 } else {
11286 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11287 res = CLI_FAILURE;
11288 }
11289 AST_LIST_UNLOCK(&zones);
11290
11291 return res;
11292 }
11293
11294
11295 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11296 {
11297 switch (cmd) {
11298 case CLI_INIT:
11299 e->command = "voicemail reload";
11300 e->usage =
11301 "Usage: voicemail reload\n"
11302 " Reload voicemail configuration\n";
11303 return NULL;
11304 case CLI_GENERATE:
11305 return NULL;
11306 }
11307
11308 if (a->argc != 2)
11309 return CLI_SHOWUSAGE;
11310
11311 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11312 load_config(1);
11313
11314 return CLI_SUCCESS;
11315 }
11316
11317 static struct ast_cli_entry cli_voicemail[] = {
11318 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11319 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11320 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11321 };
11322
11323 #ifdef IMAP_STORAGE
11324 #define DATA_EXPORT_VM_USERS(USER) \
11325 USER(ast_vm_user, context, AST_DATA_STRING) \
11326 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11327 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11328 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11329 USER(ast_vm_user, email, AST_DATA_STRING) \
11330 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11331 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11332 USER(ast_vm_user, pager, AST_DATA_STRING) \
11333 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11334 USER(ast_vm_user, language, AST_DATA_STRING) \
11335 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11336 USER(ast_vm_user, callback, AST_DATA_STRING) \
11337 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11338 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11339 USER(ast_vm_user, exit, AST_DATA_STRING) \
11340 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11341 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11342 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11343 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11344 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11345 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11346 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11347 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11348 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11349 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11350 #else
11351 #define DATA_EXPORT_VM_USERS(USER) \
11352 USER(ast_vm_user, context, AST_DATA_STRING) \
11353 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11354 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11355 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11356 USER(ast_vm_user, email, AST_DATA_STRING) \
11357 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11358 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11359 USER(ast_vm_user, pager, AST_DATA_STRING) \
11360 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11361 USER(ast_vm_user, language, AST_DATA_STRING) \
11362 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11363 USER(ast_vm_user, callback, AST_DATA_STRING) \
11364 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11365 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11366 USER(ast_vm_user, exit, AST_DATA_STRING) \
11367 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11368 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11369 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11370 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11371 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11372 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11373 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11374 #endif
11375
11376 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11377
11378 #define DATA_EXPORT_VM_ZONES(ZONE) \
11379 ZONE(vm_zone, name, AST_DATA_STRING) \
11380 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11381 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11382
11383 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11384
11385
11386
11387
11388
11389
11390
11391
11392 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11393 struct ast_data *data_root, struct ast_vm_user *user)
11394 {
11395 struct ast_data *data_user, *data_zone;
11396 struct ast_data *data_state;
11397 struct vm_zone *zone = NULL;
11398 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11399 char ext_context[256] = "";
11400
11401 data_user = ast_data_add_node(data_root, "user");
11402 if (!data_user) {
11403 return -1;
11404 }
11405
11406 ast_data_add_structure(ast_vm_user, data_user, user);
11407
11408 AST_LIST_LOCK(&zones);
11409 AST_LIST_TRAVERSE(&zones, zone, list) {
11410 if (!strcmp(zone->name, user->zonetag)) {
11411 break;
11412 }
11413 }
11414 AST_LIST_UNLOCK(&zones);
11415
11416
11417 data_state = ast_data_add_node(data_user, "state");
11418 if (!data_state) {
11419 return -1;
11420 }
11421 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11422 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11423 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11424 ast_data_add_int(data_state, "newmsg", newmsg);
11425 ast_data_add_int(data_state, "oldmsg", oldmsg);
11426
11427 if (zone) {
11428 data_zone = ast_data_add_node(data_user, "zone");
11429 ast_data_add_structure(vm_zone, data_zone, zone);
11430 }
11431
11432 if (!ast_data_search_match(search, data_user)) {
11433 ast_data_remove_node(data_root, data_user);
11434 }
11435
11436 return 0;
11437 }
11438
11439 static int vm_users_data_provider_get(const struct ast_data_search *search,
11440 struct ast_data *data_root)
11441 {
11442 struct ast_vm_user *user;
11443
11444 AST_LIST_LOCK(&users);
11445 AST_LIST_TRAVERSE(&users, user, list) {
11446 vm_users_data_provider_get_helper(search, data_root, user);
11447 }
11448 AST_LIST_UNLOCK(&users);
11449
11450 return 0;
11451 }
11452
11453 static const struct ast_data_handler vm_users_data_provider = {
11454 .version = AST_DATA_HANDLER_VERSION,
11455 .get = vm_users_data_provider_get
11456 };
11457
11458 static const struct ast_data_entry vm_data_providers[] = {
11459 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11460 };
11461
11462 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11463 {
11464 int new = 0, old = 0, urgent = 0;
11465
11466 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11467
11468 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11469 mwi_sub->old_urgent = urgent;
11470 mwi_sub->old_new = new;
11471 mwi_sub->old_old = old;
11472 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11473 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11474 }
11475 }
11476
11477 static void poll_subscribed_mailboxes(void)
11478 {
11479 struct mwi_sub *mwi_sub;
11480
11481 AST_RWLIST_RDLOCK(&mwi_subs);
11482 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11483 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11484 poll_subscribed_mailbox(mwi_sub);
11485 }
11486 }
11487 AST_RWLIST_UNLOCK(&mwi_subs);
11488 }
11489
11490 static void *mb_poll_thread(void *data)
11491 {
11492 while (poll_thread_run) {
11493 struct timespec ts = { 0, };
11494 struct timeval wait;
11495
11496 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11497 ts.tv_sec = wait.tv_sec;
11498 ts.tv_nsec = wait.tv_usec * 1000;
11499
11500 ast_mutex_lock(&poll_lock);
11501 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11502 ast_mutex_unlock(&poll_lock);
11503
11504 if (!poll_thread_run)
11505 break;
11506
11507 poll_subscribed_mailboxes();
11508 }
11509
11510 return NULL;
11511 }
11512
11513 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11514 {
11515 ast_free(mwi_sub);
11516 }
11517
11518 static int handle_unsubscribe(void *datap)
11519 {
11520 struct mwi_sub *mwi_sub;
11521 uint32_t *uniqueid = datap;
11522
11523 AST_RWLIST_WRLOCK(&mwi_subs);
11524 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11525 if (mwi_sub->uniqueid == *uniqueid) {
11526 AST_LIST_REMOVE_CURRENT(entry);
11527 break;
11528 }
11529 }
11530 AST_RWLIST_TRAVERSE_SAFE_END
11531 AST_RWLIST_UNLOCK(&mwi_subs);
11532
11533 if (mwi_sub)
11534 mwi_sub_destroy(mwi_sub);
11535
11536 ast_free(uniqueid);
11537 return 0;
11538 }
11539
11540 static int handle_subscribe(void *datap)
11541 {
11542 unsigned int len;
11543 struct mwi_sub *mwi_sub;
11544 struct mwi_sub_task *p = datap;
11545
11546 len = sizeof(*mwi_sub);
11547 if (!ast_strlen_zero(p->mailbox))
11548 len += strlen(p->mailbox);
11549
11550 if (!ast_strlen_zero(p->context))
11551 len += strlen(p->context) + 1;
11552
11553 if (!(mwi_sub = ast_calloc(1, len)))
11554 return -1;
11555
11556 mwi_sub->uniqueid = p->uniqueid;
11557 if (!ast_strlen_zero(p->mailbox))
11558 strcpy(mwi_sub->mailbox, p->mailbox);
11559
11560 if (!ast_strlen_zero(p->context)) {
11561 strcat(mwi_sub->mailbox, "@");
11562 strcat(mwi_sub->mailbox, p->context);
11563 }
11564
11565 AST_RWLIST_WRLOCK(&mwi_subs);
11566 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11567 AST_RWLIST_UNLOCK(&mwi_subs);
11568 ast_free((void *) p->mailbox);
11569 ast_free((void *) p->context);
11570 ast_free(p);
11571 poll_subscribed_mailbox(mwi_sub);
11572 return 0;
11573 }
11574
11575 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11576 {
11577 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11578
11579 if (!uniqueid) {
11580 ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n");
11581 return;
11582 }
11583
11584 if (ast_event_get_type(event) != AST_EVENT_UNSUB) {
11585 ast_free(uniqueid);
11586 return;
11587 }
11588
11589 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI) {
11590 ast_free(uniqueid);
11591 return;
11592 }
11593
11594 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11595 *uniqueid = u;
11596 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11597 ast_free(uniqueid);
11598 }
11599 }
11600
11601 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11602 {
11603 struct mwi_sub_task *mwist;
11604
11605 if (ast_event_get_type(event) != AST_EVENT_SUB)
11606 return;
11607
11608 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11609 return;
11610
11611 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11612 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11613 return;
11614 }
11615 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11616 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11617 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11618
11619 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11620 ast_free(mwist);
11621 }
11622 }
11623
11624 static void start_poll_thread(void)
11625 {
11626 int errcode;
11627 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11628 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11629 AST_EVENT_IE_END);
11630
11631 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11632 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11633 AST_EVENT_IE_END);
11634
11635 if (mwi_sub_sub)
11636 ast_event_report_subs(mwi_sub_sub);
11637
11638 poll_thread_run = 1;
11639
11640 if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL))) {
11641 ast_log(LOG_ERROR, "Could not create thread: %s\n", strerror(errcode));
11642 }
11643 }
11644
11645 static void stop_poll_thread(void)
11646 {
11647 poll_thread_run = 0;
11648
11649 if (mwi_sub_sub) {
11650 ast_event_unsubscribe(mwi_sub_sub);
11651 mwi_sub_sub = NULL;
11652 }
11653
11654 if (mwi_unsub_sub) {
11655 ast_event_unsubscribe(mwi_unsub_sub);
11656 mwi_unsub_sub = NULL;
11657 }
11658
11659 ast_mutex_lock(&poll_lock);
11660 ast_cond_signal(&poll_cond);
11661 ast_mutex_unlock(&poll_lock);
11662
11663 pthread_join(poll_thread, NULL);
11664
11665 poll_thread = AST_PTHREADT_NULL;
11666 }
11667
11668
11669 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11670 {
11671 struct ast_vm_user *vmu = NULL;
11672 const char *id = astman_get_header(m, "ActionID");
11673 char actionid[128] = "";
11674
11675 if (!ast_strlen_zero(id))
11676 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11677
11678 AST_LIST_LOCK(&users);
11679
11680 if (AST_LIST_EMPTY(&users)) {
11681 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11682 AST_LIST_UNLOCK(&users);
11683 return RESULT_SUCCESS;
11684 }
11685
11686 astman_send_ack(s, m, "Voicemail user list will follow");
11687
11688 AST_LIST_TRAVERSE(&users, vmu, list) {
11689 char dirname[256];
11690
11691 #ifdef IMAP_STORAGE
11692 int new, old;
11693 inboxcount(vmu->mailbox, &new, &old);
11694 #endif
11695
11696 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11697 astman_append(s,
11698 "%s"
11699 "Event: VoicemailUserEntry\r\n"
11700 "VMContext: %s\r\n"
11701 "VoiceMailbox: %s\r\n"
11702 "Fullname: %s\r\n"
11703 "Email: %s\r\n"
11704 "Pager: %s\r\n"
11705 "ServerEmail: %s\r\n"
11706 "MailCommand: %s\r\n"
11707 "Language: %s\r\n"
11708 "TimeZone: %s\r\n"
11709 "Callback: %s\r\n"
11710 "Dialout: %s\r\n"
11711 "UniqueID: %s\r\n"
11712 "ExitContext: %s\r\n"
11713 "SayDurationMinimum: %d\r\n"
11714 "SayEnvelope: %s\r\n"
11715 "SayCID: %s\r\n"
11716 "AttachMessage: %s\r\n"
11717 "AttachmentFormat: %s\r\n"
11718 "DeleteMessage: %s\r\n"
11719 "VolumeGain: %.2f\r\n"
11720 "CanReview: %s\r\n"
11721 "CallOperator: %s\r\n"
11722 "MaxMessageCount: %d\r\n"
11723 "MaxMessageLength: %d\r\n"
11724 "NewMessageCount: %d\r\n"
11725 #ifdef IMAP_STORAGE
11726 "OldMessageCount: %d\r\n"
11727 "IMAPUser: %s\r\n"
11728 #endif
11729 "\r\n",
11730 actionid,
11731 vmu->context,
11732 vmu->mailbox,
11733 vmu->fullname,
11734 vmu->email,
11735 vmu->pager,
11736 ast_strlen_zero(vmu->serveremail) ? serveremail : vmu->serveremail,
11737 mailcmd,
11738 vmu->language,
11739 vmu->zonetag,
11740 vmu->callback,
11741 vmu->dialout,
11742 vmu->uniqueid,
11743 vmu->exit,
11744 vmu->saydurationm,
11745 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11746 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11747 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11748 vmu->attachfmt,
11749 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11750 vmu->volgain,
11751 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11752 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11753 vmu->maxmsg,
11754 vmu->maxsecs,
11755 #ifdef IMAP_STORAGE
11756 new, old, vmu->imapuser
11757 #else
11758 count_messages(vmu, dirname)
11759 #endif
11760 );
11761 }
11762 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11763
11764 AST_LIST_UNLOCK(&users);
11765
11766 return RESULT_SUCCESS;
11767 }
11768
11769
11770 static void free_vm_users(void)
11771 {
11772 struct ast_vm_user *current;
11773 AST_LIST_LOCK(&users);
11774 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11775 ast_set_flag(current, VM_ALLOCED);
11776 free_user(current);
11777 }
11778 AST_LIST_UNLOCK(&users);
11779 }
11780
11781
11782 static void free_vm_zones(void)
11783 {
11784 struct vm_zone *zcur;
11785 AST_LIST_LOCK(&zones);
11786 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11787 free_zone(zcur);
11788 AST_LIST_UNLOCK(&zones);
11789 }
11790
11791 static const char *substitute_escapes(const char *value)
11792 {
11793 char *current;
11794
11795
11796 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11797
11798 ast_str_reset(str);
11799
11800
11801 for (current = (char *) value; *current; current++) {
11802 if (*current == '\\') {
11803 current++;
11804 if (!*current) {
11805 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11806 break;
11807 }
11808 switch (*current) {
11809 case '\\':
11810 ast_str_append(&str, 0, "\\");
11811 break;
11812 case 'r':
11813 ast_str_append(&str, 0, "\r");
11814 break;
11815 case 'n':
11816 #ifdef IMAP_STORAGE
11817 if (!str->used || str->str[str->used - 1] != '\r') {
11818 ast_str_append(&str, 0, "\r");
11819 }
11820 #endif
11821 ast_str_append(&str, 0, "\n");
11822 break;
11823 case 't':
11824 ast_str_append(&str, 0, "\t");
11825 break;
11826 default:
11827 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11828 break;
11829 }
11830 } else {
11831 ast_str_append(&str, 0, "%c", *current);
11832 }
11833 }
11834
11835 return ast_str_buffer(str);
11836 }
11837
11838 static int load_config(int reload)
11839 {
11840 struct ast_config *cfg, *ucfg;
11841 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11842 int res;
11843
11844 ast_unload_realtime("voicemail");
11845 ast_unload_realtime("voicemail_data");
11846
11847 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11848 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11849 return 0;
11850 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11851 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11852 ucfg = NULL;
11853 }
11854 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11855 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11856 ast_config_destroy(ucfg);
11857 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11858 return 0;
11859 }
11860 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11861 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11862 return 0;
11863 } else {
11864 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11865 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11866 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11867 ucfg = NULL;
11868 }
11869 }
11870
11871 res = actual_load_config(reload, cfg, ucfg);
11872
11873 ast_config_destroy(cfg);
11874 ast_config_destroy(ucfg);
11875
11876 return res;
11877 }
11878
11879 #ifdef TEST_FRAMEWORK
11880 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11881 {
11882 ast_unload_realtime("voicemail");
11883 ast_unload_realtime("voicemail_data");
11884 return actual_load_config(reload, cfg, ucfg);
11885 }
11886 #endif
11887
11888 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11889 {
11890 struct ast_vm_user *current;
11891 char *cat;
11892 struct ast_variable *var;
11893 const char *val;
11894 char *q, *stringp, *tmp;
11895 int x;
11896 int tmpadsi[4];
11897 char secretfn[PATH_MAX] = "";
11898
11899 #ifdef IMAP_STORAGE
11900 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11901 #endif
11902
11903 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11904 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11905 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11906 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11907 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11908
11909
11910 free_vm_users();
11911
11912
11913 free_vm_zones();
11914
11915 AST_LIST_LOCK(&users);
11916
11917 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11918 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11919
11920 if (cfg) {
11921
11922
11923 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11924 val = "default";
11925 ast_copy_string(userscontext, val, sizeof(userscontext));
11926
11927 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11928 val = "yes";
11929 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11930
11931 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11932 val = "no";
11933 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11934
11935 volgain = 0.0;
11936 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11937 sscanf(val, "%30lf", &volgain);
11938
11939 #ifdef ODBC_STORAGE
11940 strcpy(odbc_database, "asterisk");
11941 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11942 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11943 }
11944 strcpy(odbc_table, "voicemessages");
11945 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11946 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11947 }
11948 #endif
11949
11950 strcpy(mailcmd, SENDMAIL);
11951 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11952 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11953
11954 maxsilence = 0;
11955 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11956 maxsilence = atoi(val);
11957 if (maxsilence > 0)
11958 maxsilence *= 1000;
11959 }
11960
11961 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11962 maxmsg = MAXMSG;
11963 } else {
11964 maxmsg = atoi(val);
11965 if (maxmsg < 0) {
11966 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11967 maxmsg = MAXMSG;
11968 } else if (maxmsg > MAXMSGLIMIT) {
11969 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11970 maxmsg = MAXMSGLIMIT;
11971 }
11972 }
11973
11974 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11975 maxdeletedmsg = 0;
11976 } else {
11977 if (sscanf(val, "%30d", &x) == 1)
11978 maxdeletedmsg = x;
11979 else if (ast_true(val))
11980 maxdeletedmsg = MAXMSG;
11981 else
11982 maxdeletedmsg = 0;
11983
11984 if (maxdeletedmsg < 0) {
11985 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11986 maxdeletedmsg = MAXMSG;
11987 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11988 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11989 maxdeletedmsg = MAXMSGLIMIT;
11990 }
11991 }
11992
11993
11994 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
11995 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
11996 }
11997
11998
11999 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
12000 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
12001 }
12002
12003
12004 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
12005 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
12006 pwdchange = PWDCHANGE_EXTERNAL;
12007 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
12008 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
12009 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
12010 }
12011
12012
12013 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
12014 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
12015 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
12016 }
12017
12018 #ifdef IMAP_STORAGE
12019
12020 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
12021 ast_copy_string(imapserver, val, sizeof(imapserver));
12022 } else {
12023 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
12024 }
12025
12026 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
12027 ast_copy_string(imapport, val, sizeof(imapport));
12028 } else {
12029 ast_copy_string(imapport, "143", sizeof(imapport));
12030 }
12031
12032 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
12033 ast_copy_string(imapflags, val, sizeof(imapflags));
12034 }
12035
12036 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
12037 ast_copy_string(authuser, val, sizeof(authuser));
12038 }
12039
12040 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
12041 ast_copy_string(authpassword, val, sizeof(authpassword));
12042 }
12043
12044 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
12045 if (ast_false(val))
12046 expungeonhangup = 0;
12047 else
12048 expungeonhangup = 1;
12049 } else {
12050 expungeonhangup = 1;
12051 }
12052
12053 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
12054 ast_copy_string(imapfolder, val, sizeof(imapfolder));
12055 } else {
12056 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
12057 }
12058 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
12059 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
12060 }
12061 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
12062 imapgreetings = ast_true(val);
12063 } else {
12064 imapgreetings = 0;
12065 }
12066 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
12067 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12068 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
12069
12070 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12071 } else {
12072 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
12073 }
12074
12075
12076
12077
12078
12079 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
12080 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
12081 } else {
12082 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
12083 }
12084
12085 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
12086 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
12087 } else {
12088 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
12089 }
12090
12091 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12092 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12093 } else {
12094 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12095 }
12096
12097 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12098 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12099 } else {
12100 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12101 }
12102
12103
12104 imapversion++;
12105 #endif
12106
12107 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12108 ast_copy_string(externnotify, val, sizeof(externnotify));
12109 ast_debug(1, "found externnotify: %s\n", externnotify);
12110 } else {
12111 externnotify[0] = '\0';
12112 }
12113
12114
12115 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12116 ast_debug(1, "Enabled SMDI voicemail notification\n");
12117 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12118 smdi_iface = ast_smdi_interface_find(val);
12119 } else {
12120 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12121 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12122 }
12123 if (!smdi_iface) {
12124 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12125 }
12126 }
12127
12128
12129 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12130 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12131 silencethreshold = atoi(val);
12132
12133 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12134 val = ASTERISK_USERNAME;
12135 ast_copy_string(serveremail, val, sizeof(serveremail));
12136
12137 vmmaxsecs = 0;
12138 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
12139 if (sscanf(val, "%30d", &x) == 1) {
12140 vmmaxsecs = x;
12141 } else {
12142 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12143 }
12144 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12145 static int maxmessage_deprecate = 0;
12146 if (maxmessage_deprecate == 0) {
12147 maxmessage_deprecate = 1;
12148 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12149 }
12150 if (sscanf(val, "%30d", &x) == 1) {
12151 vmmaxsecs = x;
12152 } else {
12153 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12154 }
12155 }
12156
12157 vmminsecs = 0;
12158 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
12159 if (sscanf(val, "%30d", &x) == 1) {
12160 vmminsecs = x;
12161 if (maxsilence / 1000 >= vmminsecs) {
12162 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
12163 }
12164 } else {
12165 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12166 }
12167 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12168 static int maxmessage_deprecate = 0;
12169 if (maxmessage_deprecate == 0) {
12170 maxmessage_deprecate = 1;
12171 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12172 }
12173 if (sscanf(val, "%30d", &x) == 1) {
12174 vmminsecs = x;
12175 if (maxsilence / 1000 >= vmminsecs) {
12176 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12177 }
12178 } else {
12179 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12180 }
12181 }
12182
12183 val = ast_variable_retrieve(cfg, "general", "format");
12184 if (!val) {
12185 val = "wav";
12186 } else {
12187 tmp = ast_strdupa(val);
12188 val = ast_format_str_reduce(tmp);
12189 if (!val) {
12190 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12191 val = "wav";
12192 }
12193 }
12194 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12195
12196 skipms = 3000;
12197 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12198 if (sscanf(val, "%30d", &x) == 1) {
12199 maxgreet = x;
12200 } else {
12201 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12202 }
12203 }
12204
12205 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12206 if (sscanf(val, "%30d", &x) == 1) {
12207 skipms = x;
12208 } else {
12209 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12210 }
12211 }
12212
12213 maxlogins = 3;
12214 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12215 if (sscanf(val, "%30d", &x) == 1) {
12216 maxlogins = x;
12217 } else {
12218 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12219 }
12220 }
12221
12222 minpassword = MINPASSWORD;
12223 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12224 if (sscanf(val, "%30d", &x) == 1) {
12225 minpassword = x;
12226 } else {
12227 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12228 }
12229 }
12230
12231
12232 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12233 val = "no";
12234 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12235
12236
12237 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12238 val = "no";
12239 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12240
12241 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12242 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12243 stringp = ast_strdupa(val);
12244 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12245 if (!ast_strlen_zero(stringp)) {
12246 q = strsep(&stringp, ",");
12247 while ((*q == ' ')||(*q == '\t'))
12248 q++;
12249 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12250 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12251 } else {
12252 cidinternalcontexts[x][0] = '\0';
12253 }
12254 }
12255 }
12256 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12257 ast_debug(1, "VM Review Option disabled globally\n");
12258 val = "no";
12259 }
12260 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12261
12262
12263 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12264 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12265 val = "no";
12266 } else {
12267 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12268 }
12269 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12270 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12271 ast_debug(1, "VM next message wrap disabled globally\n");
12272 val = "no";
12273 }
12274 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12275
12276 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12277 ast_debug(1, "VM Operator break disabled globally\n");
12278 val = "no";
12279 }
12280 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12281
12282 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12283 ast_debug(1, "VM CID Info before msg disabled globally\n");
12284 val = "no";
12285 }
12286 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12287
12288 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12289 ast_debug(1, "Send Voicemail msg disabled globally\n");
12290 val = "no";
12291 }
12292 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12293
12294 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12295 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12296 val = "yes";
12297 }
12298 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12299
12300 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12301 ast_debug(1, "Move Heard enabled globally\n");
12302 val = "yes";
12303 }
12304 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12305
12306 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12307 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12308 val = "no";
12309 }
12310 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12311
12312 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12313 ast_debug(1, "Duration info before msg enabled globally\n");
12314 val = "yes";
12315 }
12316 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12317
12318 saydurationminfo = 2;
12319 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12320 if (sscanf(val, "%30d", &x) == 1) {
12321 saydurationminfo = x;
12322 } else {
12323 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12324 }
12325 }
12326
12327 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12328 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12329 val = "no";
12330 }
12331 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12332
12333 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12334 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12335 ast_debug(1, "found dialout context: %s\n", dialcontext);
12336 } else {
12337 dialcontext[0] = '\0';
12338 }
12339
12340 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12341 ast_copy_string(callcontext, val, sizeof(callcontext));
12342 ast_debug(1, "found callback context: %s\n", callcontext);
12343 } else {
12344 callcontext[0] = '\0';
12345 }
12346
12347 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12348 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12349 ast_debug(1, "found operator context: %s\n", exitcontext);
12350 } else {
12351 exitcontext[0] = '\0';
12352 }
12353
12354
12355 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12356 ast_copy_string(vm_password, val, sizeof(vm_password));
12357 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12358 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12359 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12360 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12361 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12362 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12363 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12364 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12365 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12366 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12367 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12368 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12369 }
12370 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12371 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12372 }
12373
12374 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12375 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12376 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12377 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12378 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12379 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12380 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12381 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12382 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12383 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12384
12385 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12386 val = "no";
12387 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12388
12389 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12390 val = "voicemail.conf";
12391 }
12392 if (!(strcmp(val, "spooldir"))) {
12393 passwordlocation = OPT_PWLOC_SPOOLDIR;
12394 } else {
12395 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12396 }
12397
12398 poll_freq = DEFAULT_POLL_FREQ;
12399 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12400 if (sscanf(val, "%30u", &poll_freq) != 1) {
12401 poll_freq = DEFAULT_POLL_FREQ;
12402 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12403 }
12404 }
12405
12406 poll_mailboxes = 0;
12407 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12408 poll_mailboxes = ast_true(val);
12409
12410 memset(fromstring, 0, sizeof(fromstring));
12411 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12412 strcpy(charset, "ISO-8859-1");
12413 if (emailbody) {
12414 ast_free(emailbody);
12415 emailbody = NULL;
12416 }
12417 if (emailsubject) {
12418 ast_free(emailsubject);
12419 emailsubject = NULL;
12420 }
12421 if (pagerbody) {
12422 ast_free(pagerbody);
12423 pagerbody = NULL;
12424 }
12425 if (pagersubject) {
12426 ast_free(pagersubject);
12427 pagersubject = NULL;
12428 }
12429 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12430 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12431 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12432 ast_copy_string(fromstring, val, sizeof(fromstring));
12433 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12434 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12435 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12436 ast_copy_string(charset, val, sizeof(charset));
12437 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12438 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12439 for (x = 0; x < 4; x++) {
12440 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12441 }
12442 }
12443 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12444 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12445 for (x = 0; x < 4; x++) {
12446 memcpy(&adsisec[x], &tmpadsi[x], 1);
12447 }
12448 }
12449 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12450 if (atoi(val)) {
12451 adsiver = atoi(val);
12452 }
12453 }
12454 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12455 ast_copy_string(zonetag, val, sizeof(zonetag));
12456 }
12457 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12458 ast_copy_string(locale, val, sizeof(locale));
12459 }
12460 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12461 emailsubject = ast_strdup(substitute_escapes(val));
12462 }
12463 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12464 emailbody = ast_strdup(substitute_escapes(val));
12465 }
12466 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12467 pagersubject = ast_strdup(substitute_escapes(val));
12468 }
12469 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12470 pagerbody = ast_strdup(substitute_escapes(val));
12471 }
12472
12473
12474 if (ucfg) {
12475 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12476 if (!strcasecmp(cat, "general")) {
12477 continue;
12478 }
12479 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12480 continue;
12481 if ((current = find_or_create(userscontext, cat))) {
12482 populate_defaults(current);
12483 apply_options_full(current, ast_variable_browse(ucfg, cat));
12484 ast_copy_string(current->context, userscontext, sizeof(current->context));
12485 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12486 current->passwordlocation = OPT_PWLOC_USERSCONF;
12487 }
12488
12489 switch (current->passwordlocation) {
12490 case OPT_PWLOC_SPOOLDIR:
12491 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12492 read_password_from_file(secretfn, current->password, sizeof(current->password));
12493 }
12494 }
12495 }
12496 }
12497
12498
12499 cat = ast_category_browse(cfg, NULL);
12500 while (cat) {
12501 if (strcasecmp(cat, "general")) {
12502 var = ast_variable_browse(cfg, cat);
12503 if (strcasecmp(cat, "zonemessages")) {
12504
12505 while (var) {
12506 append_mailbox(cat, var->name, var->value);
12507 var = var->next;
12508 }
12509 } else {
12510
12511 while (var) {
12512 struct vm_zone *z;
12513 if ((z = ast_malloc(sizeof(*z)))) {
12514 char *msg_format, *tzone;
12515 msg_format = ast_strdupa(var->value);
12516 tzone = strsep(&msg_format, "|,");
12517 if (msg_format) {
12518 ast_copy_string(z->name, var->name, sizeof(z->name));
12519 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12520 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12521 AST_LIST_LOCK(&zones);
12522 AST_LIST_INSERT_HEAD(&zones, z, list);
12523 AST_LIST_UNLOCK(&zones);
12524 } else {
12525 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12526 ast_free(z);
12527 }
12528 } else {
12529 AST_LIST_UNLOCK(&users);
12530 return -1;
12531 }
12532 var = var->next;
12533 }
12534 }
12535 }
12536 cat = ast_category_browse(cfg, cat);
12537 }
12538
12539 AST_LIST_UNLOCK(&users);
12540
12541 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12542 start_poll_thread();
12543 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12544 stop_poll_thread();;
12545
12546 return 0;
12547 } else {
12548 AST_LIST_UNLOCK(&users);
12549 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12550 return 0;
12551 }
12552 }
12553
12554 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12555 {
12556 int res = -1;
12557 char dir[PATH_MAX];
12558 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12559 ast_debug(2, "About to try retrieving name file %s\n", dir);
12560 RETRIEVE(dir, -1, mailbox, context);
12561 if (ast_fileexists(dir, NULL, NULL)) {
12562 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12563 }
12564 DISPOSE(dir, -1);
12565 return res;
12566 }
12567
12568 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12569 struct ast_config *pwconf;
12570 struct ast_flags config_flags = { 0 };
12571
12572 pwconf = ast_config_load(secretfn, config_flags);
12573 if (pwconf) {
12574 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12575 if (val) {
12576 ast_copy_string(password, val, passwordlen);
12577 ast_config_destroy(pwconf);
12578 return;
12579 }
12580 ast_config_destroy(pwconf);
12581 }
12582 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12583 }
12584
12585 static int write_password_to_file(const char *secretfn, const char *password) {
12586 struct ast_config *conf;
12587 struct ast_category *cat;
12588 struct ast_variable *var;
12589 int res = -1;
12590
12591 if (!(conf = ast_config_new())) {
12592 ast_log(LOG_ERROR, "Error creating new config structure\n");
12593 return res;
12594 }
12595 if (!(cat = ast_category_new("general", "", 1))) {
12596 ast_log(LOG_ERROR, "Error creating new category structure\n");
12597 ast_config_destroy(conf);
12598 return res;
12599 }
12600 if (!(var = ast_variable_new("password", password, ""))) {
12601 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12602 ast_config_destroy(conf);
12603 ast_category_destroy(cat);
12604 return res;
12605 }
12606 ast_category_append(conf, cat);
12607 ast_variable_append(cat, var);
12608 if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12609 res = 0;
12610 } else {
12611 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12612 }
12613
12614 ast_config_destroy(conf);
12615 return res;
12616 }
12617
12618 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12619 {
12620 char *context;
12621 char *args_copy;
12622 int res;
12623
12624 if (ast_strlen_zero(data)) {
12625 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context\n");
12626 return -1;
12627 }
12628
12629 args_copy = ast_strdupa(data);
12630 if ((context = strchr(args_copy, '@'))) {
12631 *context++ = '\0';
12632 } else {
12633 context = "default";
12634 }
12635
12636 if ((res = sayname(chan, args_copy, context) < 0)) {
12637 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12638 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12639 if (!res) {
12640 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12641 }
12642 }
12643
12644 return res;
12645 }
12646
12647 #ifdef TEST_FRAMEWORK
12648 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12649 {
12650 return 0;
12651 }
12652
12653 static struct ast_frame *fake_read(struct ast_channel *ast)
12654 {
12655 return &ast_null_frame;
12656 }
12657
12658 AST_TEST_DEFINE(test_voicemail_vmsayname)
12659 {
12660 char dir[PATH_MAX];
12661 char dir2[PATH_MAX];
12662 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12663 static const char TEST_EXTENSION[] = "1234";
12664
12665 struct ast_channel *test_channel1 = NULL;
12666 int res = -1;
12667
12668 static const struct ast_channel_tech fake_tech = {
12669 .write = fake_write,
12670 .read = fake_read,
12671 };
12672
12673 switch (cmd) {
12674 case TEST_INIT:
12675 info->name = "vmsayname_exec";
12676 info->category = "/apps/app_voicemail/";
12677 info->summary = "Vmsayname unit test";
12678 info->description =
12679 "This tests passing various parameters to vmsayname";
12680 return AST_TEST_NOT_RUN;
12681 case TEST_EXECUTE:
12682 break;
12683 }
12684
12685 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12686 NULL, NULL, 0, 0, "TestChannel1"))) {
12687 goto exit_vmsayname_test;
12688 }
12689
12690
12691 test_channel1->nativeformats = AST_FORMAT_GSM;
12692 test_channel1->writeformat = AST_FORMAT_GSM;
12693 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12694 test_channel1->readformat = AST_FORMAT_GSM;
12695 test_channel1->rawreadformat = AST_FORMAT_GSM;
12696 test_channel1->tech = &fake_tech;
12697
12698 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12699 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12700 if (!(res = vmsayname_exec(test_channel1, dir))) {
12701 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12702 if (ast_fileexists(dir, NULL, NULL)) {
12703 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12704 res = -1;
12705 goto exit_vmsayname_test;
12706 } else {
12707
12708 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12709 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12710 goto exit_vmsayname_test;
12711 }
12712 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12713 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12714
12715 if ((res = symlink(dir, dir2))) {
12716 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12717 goto exit_vmsayname_test;
12718 }
12719 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12720 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12721 res = vmsayname_exec(test_channel1, dir);
12722
12723
12724 unlink(dir2);
12725 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12726 rmdir(dir2);
12727 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12728 rmdir(dir2);
12729 }
12730 }
12731
12732 exit_vmsayname_test:
12733
12734 if (test_channel1) {
12735 ast_hangup(test_channel1);
12736 }
12737
12738 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12739 }
12740
12741 AST_TEST_DEFINE(test_voicemail_msgcount)
12742 {
12743 int i, j, res = AST_TEST_PASS, syserr;
12744 struct ast_vm_user *vmu;
12745 struct vm_state vms;
12746 #ifdef IMAP_STORAGE
12747 struct ast_channel *chan = NULL;
12748 #endif
12749 struct {
12750 char dir[256];
12751 char file[256];
12752 char txtfile[256];
12753 } tmp[3];
12754 char syscmd[256];
12755 const char origweasels[] = "tt-weasels";
12756 const char testcontext[] = "test";
12757 const char testmailbox[] = "00000000";
12758 const char testspec[] = "00000000@test";
12759 FILE *txt;
12760 int new, old, urgent;
12761 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12762 const int folder2mbox[3] = { 1, 11, 0 };
12763 const int expected_results[3][12] = {
12764
12765 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12766 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12767 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12768 };
12769
12770 switch (cmd) {
12771 case TEST_INIT:
12772 info->name = "test_voicemail_msgcount";
12773 info->category = "/apps/app_voicemail/";
12774 info->summary = "Test Voicemail status checks";
12775 info->description =
12776 "Verify that message counts are correct when retrieved through the public API";
12777 return AST_TEST_NOT_RUN;
12778 case TEST_EXECUTE:
12779 break;
12780 }
12781
12782
12783 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12784 if ((syserr = ast_safe_system(syscmd))) {
12785 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12786 syserr > 0 ? strerror(syserr) : "unable to fork()");
12787 return AST_TEST_FAIL;
12788 }
12789
12790 #ifdef IMAP_STORAGE
12791 if (!(chan = ast_dummy_channel_alloc())) {
12792 ast_test_status_update(test, "Unable to create dummy channel\n");
12793 return AST_TEST_FAIL;
12794 }
12795 #endif
12796
12797 if (!(vmu = find_user(NULL, testcontext, testmailbox)) &&
12798 !(vmu = find_or_create(testcontext, testmailbox))) {
12799 ast_test_status_update(test, "Cannot create vmu structure\n");
12800 ast_unreplace_sigchld();
12801 #ifdef IMAP_STORAGE
12802 chan = ast_channel_unref(chan);
12803 #endif
12804 return AST_TEST_FAIL;
12805 }
12806
12807 populate_defaults(vmu);
12808 memset(&vms, 0, sizeof(vms));
12809
12810
12811 for (i = 0; i < 3; i++) {
12812 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12813 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12814 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12815
12816 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12817 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12818 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12819 if ((syserr = ast_safe_system(syscmd))) {
12820 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12821 syserr > 0 ? strerror(syserr) : "unable to fork()");
12822 ast_unreplace_sigchld();
12823 #ifdef IMAP_STORAGE
12824 chan = ast_channel_unref(chan);
12825 #endif
12826 return AST_TEST_FAIL;
12827 }
12828 }
12829
12830 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12831 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12832 fclose(txt);
12833 } else {
12834 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12835 res = AST_TEST_FAIL;
12836 break;
12837 }
12838 open_mailbox(&vms, vmu, folder2mbox[i]);
12839 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12840
12841
12842 for (j = 0; j < 3; j++) {
12843
12844 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12845 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12846 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12847 res = AST_TEST_FAIL;
12848 }
12849 }
12850
12851 new = old = urgent = 0;
12852 if (ast_app_inboxcount(testspec, &new, &old)) {
12853 ast_test_status_update(test, "inboxcount returned failure\n");
12854 res = AST_TEST_FAIL;
12855 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12856 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12857 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12858 res = AST_TEST_FAIL;
12859 }
12860
12861 new = old = urgent = 0;
12862 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12863 ast_test_status_update(test, "inboxcount2 returned failure\n");
12864 res = AST_TEST_FAIL;
12865 } else if (old != expected_results[i][6 + 0] ||
12866 urgent != expected_results[i][6 + 1] ||
12867 new != expected_results[i][6 + 2] ) {
12868 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12869 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12870 res = AST_TEST_FAIL;
12871 }
12872
12873 new = old = urgent = 0;
12874 for (j = 0; j < 3; j++) {
12875 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12876 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12877 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12878 res = AST_TEST_FAIL;
12879 }
12880 }
12881 }
12882
12883 for (i = 0; i < 3; i++) {
12884
12885
12886
12887 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12888 DISPOSE(tmp[i].dir, 0);
12889 }
12890
12891 if (vms.deleted) {
12892 ast_free(vms.deleted);
12893 }
12894 if (vms.heard) {
12895 ast_free(vms.heard);
12896 }
12897
12898 #ifdef IMAP_STORAGE
12899 chan = ast_channel_unref(chan);
12900 #endif
12901
12902
12903 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12904 if ((syserr = ast_safe_system(syscmd))) {
12905 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12906 syserr > 0 ? strerror(syserr) : "unable to fork()");
12907 }
12908
12909 return res;
12910 }
12911
12912 AST_TEST_DEFINE(test_voicemail_notify_endl)
12913 {
12914 int res = AST_TEST_PASS;
12915 char testcontext[] = "test";
12916 char testmailbox[] = "00000000";
12917 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12918 char attach[256], attach2[256];
12919 char buf[256] = "";
12920 struct ast_channel *chan = NULL;
12921 struct ast_vm_user *vmu, vmus = {
12922 .flags = 0,
12923 };
12924 FILE *file;
12925 struct {
12926 char *name;
12927 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12928 void *location;
12929 union {
12930 int intval;
12931 char *strval;
12932 } u;
12933 } test_items[] = {
12934 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12935 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12936 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12937 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12938 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12939 { "attach2", STRPTR, attach2, .u.strval = "" },
12940 { "attach", STRPTR, attach, .u.strval = "" },
12941 };
12942 int which;
12943
12944 switch (cmd) {
12945 case TEST_INIT:
12946 info->name = "test_voicemail_notify_endl";
12947 info->category = "/apps/app_voicemail/";
12948 info->summary = "Test Voicemail notification end-of-line";
12949 info->description =
12950 "Verify that notification emails use a consistent end-of-line character";
12951 return AST_TEST_NOT_RUN;
12952 case TEST_EXECUTE:
12953 break;
12954 }
12955
12956 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12957 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12958
12959 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12960 !(vmu = find_or_create(testcontext, testmailbox))) {
12961 ast_test_status_update(test, "Cannot create vmu structure\n");
12962 return AST_TEST_NOT_RUN;
12963 }
12964
12965 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12966 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12967 return AST_TEST_NOT_RUN;
12968 }
12969
12970 populate_defaults(vmu);
12971 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12972 #ifdef IMAP_STORAGE
12973
12974 #endif
12975
12976 file = tmpfile();
12977 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12978
12979 rewind(file);
12980 if (ftruncate(fileno(file), 0)) {
12981 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12982 res = AST_TEST_FAIL;
12983 break;
12984 }
12985
12986
12987 if (test_items[which].type == INT) {
12988 *((int *) test_items[which].location) = test_items[which].u.intval;
12989 } else if (test_items[which].type == FLAGVAL) {
12990 if (ast_test_flag(vmu, test_items[which].u.intval)) {
12991 ast_clear_flag(vmu, test_items[which].u.intval);
12992 } else {
12993 ast_set_flag(vmu, test_items[which].u.intval);
12994 }
12995 } else if (test_items[which].type == STATIC) {
12996 strcpy(test_items[which].location, test_items[which].u.strval);
12997 } else if (test_items[which].type == STRPTR) {
12998 test_items[which].location = test_items[which].u.strval;
12999 }
13000
13001 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
13002 rewind(file);
13003 while (fgets(buf, sizeof(buf), file)) {
13004 if (
13005 #ifdef IMAP_STORAGE
13006 buf[strlen(buf) - 2] != '\r'
13007 #else
13008 buf[strlen(buf) - 2] == '\r'
13009 #endif
13010 || buf[strlen(buf) - 1] != '\n') {
13011 res = AST_TEST_FAIL;
13012 }
13013 }
13014 }
13015 fclose(file);
13016 return res;
13017 }
13018
13019 AST_TEST_DEFINE(test_voicemail_load_config)
13020 {
13021 int res = AST_TEST_PASS;
13022 struct ast_vm_user *vmu;
13023 struct ast_config *cfg;
13024 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
13025 int fd;
13026 FILE *file;
13027 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
13028
13029 switch (cmd) {
13030 case TEST_INIT:
13031 info->name = "test_voicemail_load_config";
13032 info->category = "/apps/app_voicemail/";
13033 info->summary = "Test loading Voicemail config";
13034 info->description =
13035 "Verify that configuration is loaded consistently. "
13036 "This is to test regressions of ASTERISK-18838 where it was noticed that "
13037 "some options were loaded after the mailboxes were instantiated, causing "
13038 "those options not to be set correctly.";
13039 return AST_TEST_NOT_RUN;
13040 case TEST_EXECUTE:
13041 break;
13042 }
13043
13044
13045 if ((fd = mkstemp(config_filename)) < 0) {
13046 return AST_TEST_FAIL;
13047 }
13048 if (!(file = fdopen(fd, "w"))) {
13049 close(fd);
13050 unlink(config_filename);
13051 return AST_TEST_FAIL;
13052 }
13053 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
13054 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
13055 fputs("00000002 => 9999,Mrs. Test\n", file);
13056 fclose(file);
13057
13058 if (!(cfg = ast_config_load(config_filename, config_flags))) {
13059 res = AST_TEST_FAIL;
13060 goto cleanup;
13061 }
13062
13063 load_config_from_memory(1, cfg, NULL);
13064 ast_config_destroy(cfg);
13065
13066 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
13067 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
13068 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
13069
13070 AST_LIST_LOCK(&users);
13071 AST_LIST_TRAVERSE(&users, vmu, list) {
13072 if (!strcmp(vmu->mailbox, "00000001")) {
13073 if (0);
13074 CHECK(vmu, callback, "othercontext")
13075 CHECK(vmu, locale, "nl_NL.UTF-8")
13076 CHECK(vmu, zonetag, "central")
13077 } else if (!strcmp(vmu->mailbox, "00000002")) {
13078 if (0);
13079 CHECK(vmu, callback, "somecontext")
13080 CHECK(vmu, locale, "de_DE.UTF-8")
13081 CHECK(vmu, zonetag, "european")
13082 }
13083 }
13084 AST_LIST_UNLOCK(&users);
13085
13086 #undef CHECK
13087
13088
13089 load_config(1);
13090
13091 cleanup:
13092 unlink(config_filename);
13093 return res;
13094 }
13095
13096 #endif
13097
13098 static int reload(void)
13099 {
13100 return load_config(1);
13101 }
13102
13103 static int unload_module(void)
13104 {
13105 int res;
13106
13107 res = ast_unregister_application(app);
13108 res |= ast_unregister_application(app2);
13109 res |= ast_unregister_application(app3);
13110 res |= ast_unregister_application(app4);
13111 res |= ast_unregister_application(sayname_app);
13112 res |= ast_custom_function_unregister(&mailbox_exists_acf);
13113 res |= ast_manager_unregister("VoicemailUsersList");
13114 res |= ast_data_unregister(NULL);
13115 #ifdef TEST_FRAMEWORK
13116 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
13117 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
13118 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
13119 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
13120 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
13121 #endif
13122 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13123 ast_uninstall_vm_functions();
13124 ao2_ref(inprocess_container, -1);
13125
13126 if (poll_thread != AST_PTHREADT_NULL)
13127 stop_poll_thread();
13128
13129 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
13130 ast_unload_realtime("voicemail");
13131 ast_unload_realtime("voicemail_data");
13132
13133 free_vm_users();
13134 free_vm_zones();
13135 return res;
13136 }
13137
13138 static int load_module(void)
13139 {
13140 int res;
13141 my_umask = umask(0);
13142 umask(my_umask);
13143
13144 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
13145 return AST_MODULE_LOAD_DECLINE;
13146 }
13147
13148
13149 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
13150
13151 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
13152 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
13153 }
13154
13155 if ((res = load_config(0)))
13156 return res;
13157
13158 res = ast_register_application_xml(app, vm_exec);
13159 res |= ast_register_application_xml(app2, vm_execmain);
13160 res |= ast_register_application_xml(app3, vm_box_exists);
13161 res |= ast_register_application_xml(app4, vmauthenticate);
13162 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
13163 res |= ast_custom_function_register(&mailbox_exists_acf);
13164 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
13165 #ifdef TEST_FRAMEWORK
13166 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
13167 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
13168 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
13169 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
13170 res |= AST_TEST_REGISTER(test_voicemail_load_config);
13171 #endif
13172
13173 if (res)
13174 return res;
13175
13176 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13177 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
13178
13179 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
13180 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
13181 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
13182
13183 return res;
13184 }
13185
13186 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13187 {
13188 int cmd = 0;
13189 char destination[80] = "";
13190 int retries = 0;
13191
13192 if (!num) {
13193 ast_verb(3, "Destination number will be entered manually\n");
13194 while (retries < 3 && cmd != 't') {
13195 destination[1] = '\0';
13196 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13197 if (!cmd)
13198 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13199 if (!cmd)
13200 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13201 if (!cmd) {
13202 cmd = ast_waitfordigit(chan, 6000);
13203 if (cmd)
13204 destination[0] = cmd;
13205 }
13206 if (!cmd) {
13207 retries++;
13208 } else {
13209
13210 if (cmd < 0)
13211 return 0;
13212 if (cmd == '*') {
13213 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13214 return 0;
13215 }
13216 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13217 retries++;
13218 else
13219 cmd = 't';
13220 }
13221 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13222 }
13223 if (retries >= 3) {
13224 return 0;
13225 }
13226
13227 } else {
13228 if (option_verbose > 2)
13229 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
13230 ast_copy_string(destination, num, sizeof(destination));
13231 }
13232
13233 if (!ast_strlen_zero(destination)) {
13234 if (destination[strlen(destination) -1 ] == '*')
13235 return 0;
13236 if (option_verbose > 2)
13237 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13238 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13239 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13240 chan->priority = 0;
13241 return 9;
13242 }
13243 return 0;
13244 }
13245
13246
13247
13248
13249
13250
13251
13252
13253
13254
13255
13256
13257
13258
13259 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)
13260 {
13261 int res = 0;
13262 char filename[PATH_MAX];
13263 struct ast_config *msg_cfg = NULL;
13264 const char *origtime, *context;
13265 char *name, *num;
13266 int retries = 0;
13267 char *cid;
13268 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13269
13270 vms->starting = 0;
13271
13272 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13273
13274
13275 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13276 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13277 msg_cfg = ast_config_load(filename, config_flags);
13278 DISPOSE(vms->curdir, vms->curmsg);
13279 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
13280 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13281 return 0;
13282 }
13283
13284 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13285 ast_config_destroy(msg_cfg);
13286 return 0;
13287 }
13288
13289 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13290
13291 context = ast_variable_retrieve(msg_cfg, "message", "context");
13292 if (!strncasecmp("macro", context, 5))
13293 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13294 switch (option) {
13295 case 3:
13296 if (!res)
13297 res = play_message_datetime(chan, vmu, origtime, filename);
13298 if (!res)
13299 res = play_message_callerid(chan, vms, cid, context, 0);
13300
13301 res = 't';
13302 break;
13303
13304 case 2:
13305
13306 if (ast_strlen_zero(cid))
13307 break;
13308
13309 ast_callerid_parse(cid, &name, &num);
13310 while ((res > -1) && (res != 't')) {
13311 switch (res) {
13312 case '1':
13313 if (num) {
13314
13315 res = dialout(chan, vmu, num, vmu->callback);
13316 if (res) {
13317 ast_config_destroy(msg_cfg);
13318 return 9;
13319 }
13320 } else {
13321 res = '2';
13322 }
13323 break;
13324
13325 case '2':
13326
13327 if (!ast_strlen_zero(vmu->dialout)) {
13328 res = dialout(chan, vmu, NULL, vmu->dialout);
13329 if (res) {
13330 ast_config_destroy(msg_cfg);
13331 return 9;
13332 }
13333 } else {
13334 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13335 res = ast_play_and_wait(chan, "vm-sorry");
13336 }
13337 ast_config_destroy(msg_cfg);
13338 return res;
13339 case '*':
13340 res = 't';
13341 break;
13342 case '3':
13343 case '4':
13344 case '5':
13345 case '6':
13346 case '7':
13347 case '8':
13348 case '9':
13349 case '0':
13350
13351 res = ast_play_and_wait(chan, "vm-sorry");
13352 retries++;
13353 break;
13354 default:
13355 if (num) {
13356 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13357 res = ast_play_and_wait(chan, "vm-num-i-have");
13358 if (!res)
13359 res = play_message_callerid(chan, vms, num, vmu->context, 1);
13360 if (!res)
13361 res = ast_play_and_wait(chan, "vm-tocallnum");
13362
13363 if (!ast_strlen_zero(vmu->dialout)) {
13364 if (!res)
13365 res = ast_play_and_wait(chan, "vm-calldiffnum");
13366 }
13367 } else {
13368 res = ast_play_and_wait(chan, "vm-nonumber");
13369 if (!ast_strlen_zero(vmu->dialout)) {
13370 if (!res)
13371 res = ast_play_and_wait(chan, "vm-toenternumber");
13372 }
13373 }
13374 if (!res) {
13375 res = ast_play_and_wait(chan, "vm-star-cancel");
13376 }
13377 if (!res) {
13378 res = ast_waitfordigit(chan, 6000);
13379 }
13380 if (!res) {
13381 retries++;
13382 if (retries > 3) {
13383 res = 't';
13384 }
13385 }
13386 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13387 break;
13388
13389 }
13390 if (res == 't')
13391 res = 0;
13392 else if (res == '*')
13393 res = -1;
13394 }
13395 break;
13396
13397 case 1:
13398
13399 if (ast_strlen_zero(cid))
13400 break;
13401
13402 ast_callerid_parse(cid, &name, &num);
13403 if (!num) {
13404 ast_verb(3, "No CID number available, no reply sent\n");
13405 if (!res)
13406 res = ast_play_and_wait(chan, "vm-nonumber");
13407 ast_config_destroy(msg_cfg);
13408 return res;
13409 } else {
13410 struct ast_vm_user vmu2;
13411 if (find_user(&vmu2, vmu->context, num)) {
13412 struct leave_vm_options leave_options;
13413 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13414 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13415
13416 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13417
13418 memset(&leave_options, 0, sizeof(leave_options));
13419 leave_options.record_gain = record_gain;
13420 res = leave_voicemail(chan, mailbox, &leave_options);
13421 if (!res)
13422 res = 't';
13423 ast_config_destroy(msg_cfg);
13424 return res;
13425 } else {
13426
13427 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13428 ast_play_and_wait(chan, "vm-nobox");
13429 res = 't';
13430 ast_config_destroy(msg_cfg);
13431 return res;
13432 }
13433 }
13434 res = 0;
13435
13436 break;
13437 }
13438
13439 #ifndef IMAP_STORAGE
13440 ast_config_destroy(msg_cfg);
13441
13442 if (!res) {
13443 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13444 vms->heard[msg] = 1;
13445 res = wait_file(chan, vms, vms->fn);
13446 }
13447 #endif
13448 return res;
13449 }
13450
13451 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13452 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
13453 signed char record_gain, struct vm_state *vms, char *flag)
13454 {
13455
13456 int res = 0;
13457 int cmd = 0;
13458 int max_attempts = 3;
13459 int attempts = 0;
13460 int recorded = 0;
13461 int msg_exists = 0;
13462 signed char zero_gain = 0;
13463 char tempfile[PATH_MAX];
13464 char *acceptdtmf = "#";
13465 char *canceldtmf = "";
13466 int canceleddtmf = 0;
13467
13468
13469
13470
13471 if (duration == NULL) {
13472 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13473 return -1;
13474 }
13475
13476 if (!outsidecaller)
13477 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13478 else
13479 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13480
13481 cmd = '3';
13482
13483 while ((cmd >= 0) && (cmd != 't')) {
13484 switch (cmd) {
13485 case '1':
13486 if (!msg_exists) {
13487
13488 cmd = '3';
13489 break;
13490 } else {
13491
13492 ast_verb(3, "Saving message as is\n");
13493 if (!outsidecaller)
13494 ast_filerename(tempfile, recordfile, NULL);
13495 ast_stream_and_wait(chan, "vm-msgsaved", "");
13496 if (!outsidecaller) {
13497
13498 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13499 DISPOSE(recordfile, -1);
13500 }
13501 cmd = 't';
13502 return res;
13503 }
13504 case '2':
13505
13506 ast_verb(3, "Reviewing the message\n");
13507 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13508 break;
13509 case '3':
13510 msg_exists = 0;
13511
13512 if (recorded == 1)
13513 ast_verb(3, "Re-recording the message\n");
13514 else
13515 ast_verb(3, "Recording the message\n");
13516
13517 if (recorded && outsidecaller) {
13518 cmd = ast_play_and_wait(chan, INTRO);
13519 cmd = ast_play_and_wait(chan, "beep");
13520 }
13521 recorded = 1;
13522
13523 if (record_gain)
13524 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13525 if (ast_test_flag(vmu, VM_OPERATOR))
13526 canceldtmf = "0";
13527 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13528 if (strchr(canceldtmf, cmd)) {
13529
13530 canceleddtmf = 1;
13531 }
13532 if (record_gain)
13533 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13534 if (cmd == -1) {
13535
13536 if (!outsidecaller) {
13537
13538 ast_filedelete(tempfile, NULL);
13539 }
13540 return cmd;
13541 }
13542 if (cmd == '0') {
13543 break;
13544 } else if (cmd == '*') {
13545 break;
13546 #if 0
13547 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13548
13549 ast_verb(3, "Message too short\n");
13550 cmd = ast_play_and_wait(chan, "vm-tooshort");
13551 cmd = ast_filedelete(tempfile, NULL);
13552 break;
13553 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13554
13555 ast_verb(3, "Nothing recorded\n");
13556 cmd = ast_filedelete(tempfile, NULL);
13557 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13558 if (!cmd)
13559 cmd = ast_play_and_wait(chan, "vm-speakup");
13560 break;
13561 #endif
13562 } else {
13563
13564 msg_exists = 1;
13565 cmd = 0;
13566 }
13567 break;
13568 case '4':
13569 if (outsidecaller) {
13570
13571 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13572 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13573 res = ast_play_and_wait(chan, "vm-marked-urgent");
13574 strcpy(flag, "Urgent");
13575 } else if (flag) {
13576 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13577 res = ast_play_and_wait(chan, "vm-marked-nonurgent");
13578 strcpy(flag, "");
13579 } else {
13580 ast_play_and_wait(chan, "vm-sorry");
13581 }
13582 cmd = 0;
13583 } else {
13584 cmd = ast_play_and_wait(chan, "vm-sorry");
13585 }
13586 break;
13587 case '5':
13588 case '6':
13589 case '7':
13590 case '8':
13591 case '9':
13592 case '*':
13593 case '#':
13594 cmd = ast_play_and_wait(chan, "vm-sorry");
13595 break;
13596 #if 0
13597
13598
13599 case '*':
13600
13601 cmd = ast_play_and_wait(chan, "vm-deleted");
13602 cmd = ast_filedelete(tempfile, NULL);
13603 if (outsidecaller) {
13604 res = vm_exec(chan, NULL);
13605 return res;
13606 }
13607 else
13608 return 1;
13609 #endif
13610 case '0':
13611 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13612 cmd = ast_play_and_wait(chan, "vm-sorry");
13613 break;
13614 }
13615 if (msg_exists || recorded) {
13616 cmd = ast_play_and_wait(chan, "vm-saveoper");
13617 if (!cmd)
13618 cmd = ast_waitfordigit(chan, 3000);
13619 if (cmd == '1') {
13620 ast_filerename(tempfile, recordfile, NULL);
13621 ast_play_and_wait(chan, "vm-msgsaved");
13622 cmd = '0';
13623 } else if (cmd == '4') {
13624 if (flag) {
13625 ast_play_and_wait(chan, "vm-marked-urgent");
13626 strcpy(flag, "Urgent");
13627 }
13628 ast_play_and_wait(chan, "vm-msgsaved");
13629 cmd = '0';
13630 } else {
13631 ast_play_and_wait(chan, "vm-deleted");
13632 DELETE(tempfile, -1, tempfile, vmu);
13633 cmd = '0';
13634 }
13635 }
13636 return cmd;
13637 default:
13638
13639
13640
13641 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13642 return cmd;
13643 if (msg_exists) {
13644 cmd = ast_play_and_wait(chan, "vm-review");
13645 if (!cmd && outsidecaller) {
13646 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13647 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13648 } else if (flag) {
13649 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13650 }
13651 }
13652 } else {
13653 cmd = ast_play_and_wait(chan, "vm-torerecord");
13654 if (!cmd)
13655 cmd = ast_waitfordigit(chan, 600);
13656 }
13657
13658 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13659 cmd = ast_play_and_wait(chan, "vm-reachoper");
13660 if (!cmd)
13661 cmd = ast_waitfordigit(chan, 600);
13662 }
13663 #if 0
13664 if (!cmd)
13665 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13666 #endif
13667 if (!cmd)
13668 cmd = ast_waitfordigit(chan, 6000);
13669 if (!cmd) {
13670 attempts++;
13671 }
13672 if (attempts > max_attempts) {
13673 cmd = 't';
13674 }
13675 }
13676 }
13677 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13678
13679 ast_filedelete(tempfile, NULL);
13680 }
13681
13682 if (cmd != 't' && outsidecaller)
13683 ast_play_and_wait(chan, "vm-goodbye");
13684
13685 return cmd;
13686 }
13687
13688
13689
13690
13691
13692 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13693 .load = load_module,
13694 .unload = unload_module,
13695 .reload = reload,
13696 .nonoptreq = "res_adsi,res_smdi",
13697 );