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: 421125 $")
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 static inline int valid_config(const struct ast_config *cfg)
01514 {
01515 return cfg && cfg != CONFIG_STATUS_FILEINVALID;
01516 }
01517
01518
01519
01520
01521
01522
01523
01524
01525 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01526 {
01527 struct ast_config *cfg = NULL;
01528 struct ast_variable *var = NULL;
01529 struct ast_category *cat = NULL;
01530 char *category = NULL, *value = NULL, *new = NULL;
01531 const char *tmp = NULL;
01532 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01533 char secretfn[PATH_MAX] = "";
01534 int found = 0;
01535
01536 if (!change_password_realtime(vmu, newpassword))
01537 return;
01538
01539
01540 switch (vmu->passwordlocation) {
01541 case OPT_PWLOC_SPOOLDIR:
01542 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01543 if (write_password_to_file(secretfn, newpassword) == 0) {
01544 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
01545 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01546 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01547 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01548 break;
01549 } else {
01550 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01551 }
01552
01553 case OPT_PWLOC_VOICEMAILCONF:
01554 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && valid_config(cfg)) {
01555 while ((category = ast_category_browse(cfg, category))) {
01556 if (!strcasecmp(category, vmu->context)) {
01557 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01558 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01559 break;
01560 }
01561 value = strstr(tmp, ",");
01562 if (!value) {
01563 new = ast_alloca(strlen(newpassword)+1);
01564 sprintf(new, "%s", newpassword);
01565 } else {
01566 new = ast_alloca((strlen(value) + strlen(newpassword) + 1));
01567 sprintf(new, "%s%s", newpassword, value);
01568 }
01569 if (!(cat = ast_category_get(cfg, category))) {
01570 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01571 break;
01572 }
01573 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01574 found = 1;
01575 }
01576 }
01577
01578 if (found) {
01579 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
01580 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01581 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01582 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01583 ast_config_destroy(cfg);
01584 break;
01585 }
01586
01587 ast_config_destroy(cfg);
01588 }
01589
01590 case OPT_PWLOC_USERSCONF:
01591
01592
01593 if ((cfg = ast_config_load("users.conf", config_flags)) && valid_config(cfg)) {
01594 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01595 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01596 ast_debug(4, "users.conf: %s\n", category);
01597 if (!strcasecmp(category, vmu->mailbox)) {
01598 if (!ast_variable_retrieve(cfg, category, "vmsecret")) {
01599 ast_debug(3, "looks like we need to make vmsecret!\n");
01600 var = ast_variable_new("vmsecret", newpassword, "");
01601 } else {
01602 var = NULL;
01603 }
01604 new = ast_alloca(strlen(newpassword) + 1);
01605 sprintf(new, "%s", newpassword);
01606 if (!(cat = ast_category_get(cfg, category))) {
01607 ast_debug(4, "failed to get category!\n");
01608 ast_free(var);
01609 break;
01610 }
01611 if (!var) {
01612 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01613 } else {
01614 ast_variable_append(cat, var);
01615 }
01616 found = 1;
01617 break;
01618 }
01619 }
01620
01621 if (found) {
01622 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
01623 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01624 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01625 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01626 }
01627
01628 ast_config_destroy(cfg);
01629 }
01630 }
01631 }
01632
01633 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01634 {
01635 char buf[255];
01636 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01637 ast_debug(1, "External password: %s\n",buf);
01638 if (!ast_safe_system(buf)) {
01639 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
01640 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01641
01642 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01643 }
01644 }
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01660 {
01661 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01662 }
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676 static int make_file(char *dest, const int len, const char *dir, const int num)
01677 {
01678 return snprintf(dest, len, "%s/msg%04d", dir, num);
01679 }
01680
01681
01682 static FILE *vm_mkftemp(char *template)
01683 {
01684 FILE *p = NULL;
01685 int pfd = mkstemp(template);
01686 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01687 if (pfd > -1) {
01688 p = fdopen(pfd, "w+");
01689 if (!p) {
01690 close(pfd);
01691 pfd = -1;
01692 }
01693 }
01694 return p;
01695 }
01696
01697
01698
01699
01700
01701
01702
01703
01704
01705 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01706 {
01707 mode_t mode = VOICEMAIL_DIR_MODE;
01708 int res;
01709
01710 make_dir(dest, len, context, ext, folder);
01711 if ((res = ast_mkdir(dest, mode))) {
01712 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01713 return -1;
01714 }
01715 return 0;
01716 }
01717
01718 static const char * const mailbox_folders[] = {
01719 #ifdef IMAP_STORAGE
01720 imapfolder,
01721 #else
01722 "INBOX",
01723 #endif
01724 "Old",
01725 "Work",
01726 "Family",
01727 "Friends",
01728 "Cust1",
01729 "Cust2",
01730 "Cust3",
01731 "Cust4",
01732 "Cust5",
01733 "Deleted",
01734 "Urgent",
01735 };
01736
01737 static const char *mbox(struct ast_vm_user *vmu, int id)
01738 {
01739 #ifdef IMAP_STORAGE
01740 if (vmu && id == 0) {
01741 return vmu->imapfolder;
01742 }
01743 #endif
01744 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01745 }
01746
01747 static int get_folder_by_name(const char *name)
01748 {
01749 size_t i;
01750
01751 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01752 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01753 return i;
01754 }
01755 }
01756
01757 return -1;
01758 }
01759
01760 static void free_user(struct ast_vm_user *vmu)
01761 {
01762 if (ast_test_flag(vmu, VM_ALLOCED)) {
01763
01764 ast_free(vmu->emailbody);
01765 vmu->emailbody = NULL;
01766
01767 ast_free(vmu->emailsubject);
01768 vmu->emailsubject = NULL;
01769
01770 ast_free(vmu);
01771 }
01772 }
01773
01774 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01775
01776 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01777
01778
01779 if (vms->deleted) {
01780 ast_free(vms->deleted);
01781 vms->deleted = NULL;
01782 }
01783 if (vms->heard) {
01784 ast_free(vms->heard);
01785 vms->heard = NULL;
01786 }
01787 vms->dh_arraysize = 0;
01788
01789 if (arraysize > 0) {
01790 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01791 return -1;
01792 }
01793 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01794 ast_free(vms->deleted);
01795 vms->deleted = NULL;
01796 return -1;
01797 }
01798 vms->dh_arraysize = arraysize;
01799 }
01800
01801 return 0;
01802 }
01803
01804
01805
01806 #ifdef IMAP_STORAGE
01807 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01808 {
01809 char arg[10];
01810 struct vm_state *vms;
01811 unsigned long messageNum;
01812
01813
01814 if (msgnum < 0 && !imapgreetings) {
01815 ast_filedelete(file, NULL);
01816 return;
01817 }
01818
01819 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01820 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);
01821 return;
01822 }
01823
01824 if (msgnum < 0) {
01825 imap_delete_old_greeting(file, vms);
01826 return;
01827 }
01828
01829
01830
01831 messageNum = vms->msgArray[msgnum];
01832 if (messageNum == 0) {
01833 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01834 return;
01835 }
01836 if (option_debug > 2)
01837 ast_log(LOG_DEBUG, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01838
01839 snprintf (arg, sizeof(arg), "%lu", messageNum);
01840 ast_mutex_lock(&vms->lock);
01841 mail_setflag (vms->mailstream, arg, "\\DELETED");
01842 mail_expunge(vms->mailstream);
01843 ast_mutex_unlock(&vms->lock);
01844 }
01845
01846 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
01847 {
01848 struct vm_state *vms_p;
01849 char *file, *filename;
01850 char *attachment;
01851 int i;
01852 BODY *body;
01853
01854
01855
01856
01857 if (msgnum > -1 || !imapgreetings) {
01858 return 0;
01859 } else {
01860 file = strrchr(ast_strdupa(dir), '/');
01861 if (file)
01862 *file++ = '\0';
01863 else {
01864 ast_debug (1, "Failed to procure file name from directory passed.\n");
01865 return -1;
01866 }
01867 }
01868
01869
01870 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
01871 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01872
01873
01874
01875
01876 if (!(vms_p = create_vm_state_from_user(vmu))) {
01877 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
01878 return -1;
01879 }
01880 }
01881
01882
01883 *vms_p->introfn = '\0';
01884
01885 ast_mutex_lock(&vms_p->lock);
01886 init_mailstream(vms_p, GREETINGS_FOLDER);
01887 if (!vms_p->mailstream) {
01888 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL\n");
01889 ast_mutex_unlock(&vms_p->lock);
01890 return -1;
01891 }
01892
01893
01894 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
01895 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
01896
01897 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01898 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
01899 } else {
01900 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
01901 ast_mutex_unlock(&vms_p->lock);
01902 return -1;
01903 }
01904 filename = strsep(&attachment, ".");
01905 if (!strcmp(filename, file)) {
01906 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
01907 vms_p->msgArray[vms_p->curmsg] = i + 1;
01908 save_body(body, vms_p, "2", attachment, 0);
01909 ast_mutex_unlock(&vms_p->lock);
01910 return 0;
01911 }
01912 }
01913 ast_mutex_unlock(&vms_p->lock);
01914
01915 return -1;
01916 }
01917
01918 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
01919 {
01920 BODY *body;
01921 char *header_content;
01922 char *attachedfilefmt;
01923 char buf[80];
01924 struct vm_state *vms;
01925 char text_file[PATH_MAX];
01926 FILE *text_file_ptr;
01927 int res = 0;
01928 struct ast_vm_user *vmu;
01929
01930 if (!(vmu = find_user(NULL, context, mailbox))) {
01931 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
01932 return -1;
01933 }
01934
01935 if (msgnum < 0) {
01936 if (imapgreetings) {
01937 res = imap_retrieve_greeting(dir, msgnum, vmu);
01938 goto exit;
01939 } else {
01940 res = 0;
01941 goto exit;
01942 }
01943 }
01944
01945
01946
01947
01948 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01949
01950
01951
01952
01953
01954
01955
01956 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
01957 res = -1;
01958 goto exit;
01959 }
01960
01961 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
01962 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
01963
01964
01965 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
01966 res = 0;
01967 goto exit;
01968 }
01969
01970 if (option_debug > 2)
01971 ast_log(LOG_DEBUG, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
01972 if (vms->msgArray[msgnum] == 0) {
01973 ast_log(LOG_WARNING, "Trying to access unknown message\n");
01974 res = -1;
01975 goto exit;
01976 }
01977
01978
01979 ast_mutex_lock(&vms->lock);
01980 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
01981 ast_mutex_unlock(&vms->lock);
01982
01983 if (ast_strlen_zero(header_content)) {
01984 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
01985 res = -1;
01986 goto exit;
01987 }
01988
01989 ast_mutex_lock(&vms->lock);
01990 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
01991 ast_mutex_unlock(&vms->lock);
01992
01993
01994 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
01995 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
01996 } else {
01997 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
01998 res = -1;
01999 goto exit;
02000 }
02001
02002
02003
02004 strsep(&attachedfilefmt, ".");
02005 if (!attachedfilefmt) {
02006 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
02007 res = -1;
02008 goto exit;
02009 }
02010
02011 save_body(body, vms, "2", attachedfilefmt, 0);
02012 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
02013 *vms->introfn = '\0';
02014 }
02015
02016
02017 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
02018
02019 if (!(text_file_ptr = fopen(text_file, "w"))) {
02020 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
02021 }
02022
02023 fprintf(text_file_ptr, "%s\n", "[message]");
02024
02025 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf));
02026 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
02027 get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf));
02028 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
02029 get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf));
02030 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
02031 get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf));
02032 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
02033 get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf));
02034 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
02035 get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf));
02036 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
02037 get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf));
02038 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
02039 fclose(text_file_ptr);
02040
02041 exit:
02042 free_user(vmu);
02043 return res;
02044 }
02045
02046 static int folder_int(const char *folder)
02047 {
02048
02049 if (!folder) {
02050 return 0;
02051 }
02052 if (!strcasecmp(folder, imapfolder)) {
02053 return 0;
02054 } else if (!strcasecmp(folder, "Old")) {
02055 return 1;
02056 } else if (!strcasecmp(folder, "Work")) {
02057 return 2;
02058 } else if (!strcasecmp(folder, "Family")) {
02059 return 3;
02060 } else if (!strcasecmp(folder, "Friends")) {
02061 return 4;
02062 } else if (!strcasecmp(folder, "Cust1")) {
02063 return 5;
02064 } else if (!strcasecmp(folder, "Cust2")) {
02065 return 6;
02066 } else if (!strcasecmp(folder, "Cust3")) {
02067 return 7;
02068 } else if (!strcasecmp(folder, "Cust4")) {
02069 return 8;
02070 } else if (!strcasecmp(folder, "Cust5")) {
02071 return 9;
02072 } else if (!strcasecmp(folder, "Urgent")) {
02073 return 11;
02074 } else {
02075 return 0;
02076 }
02077 }
02078
02079 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02080 {
02081 SEARCHPGM *pgm;
02082 SEARCHHEADER *hdr;
02083
02084 struct ast_vm_user *vmu, vmus;
02085 struct vm_state *vms_p;
02086 int ret = 0;
02087 int fold = folder_int(folder);
02088 int urgent = 0;
02089
02090
02091 if (fold == 11) {
02092 fold = NEW_FOLDER;
02093 urgent = 1;
02094 }
02095
02096 if (ast_strlen_zero(mailbox))
02097 return 0;
02098
02099
02100 vmu = find_user(&vmus, context, mailbox);
02101 if (!vmu) {
02102 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02103 return -1;
02104 } else {
02105
02106 if (vmu->imapuser[0] == '\0') {
02107 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02108 return -1;
02109 }
02110 }
02111
02112
02113 if (vmu->imapuser[0] == '\0') {
02114 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02115 free_user(vmu);
02116 return -1;
02117 }
02118
02119
02120 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02121 if (!vms_p) {
02122 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02123 }
02124 if (vms_p) {
02125 ast_debug(3, "Returning before search - user is logged in\n");
02126 if (fold == 0) {
02127 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02128 }
02129 if (fold == 1) {
02130 return vms_p->oldmessages;
02131 }
02132 }
02133
02134
02135 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02136 if (!vms_p) {
02137 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02138 }
02139
02140 if (!vms_p) {
02141 vms_p = create_vm_state_from_user(vmu);
02142 }
02143 ret = init_mailstream(vms_p, fold);
02144 if (!vms_p->mailstream) {
02145 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02146 return -1;
02147 }
02148 if (ret == 0) {
02149 ast_mutex_lock(&vms_p->lock);
02150 pgm = mail_newsearchpgm ();
02151 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02152 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02153 pgm->header = hdr;
02154 if (fold != OLD_FOLDER) {
02155 pgm->unseen = 1;
02156 pgm->seen = 0;
02157 }
02158
02159
02160
02161 else {
02162 pgm->unseen = 0;
02163 pgm->seen = 1;
02164 }
02165
02166 if (fold == NEW_FOLDER) {
02167 if (urgent) {
02168 pgm->flagged = 1;
02169 pgm->unflagged = 0;
02170 } else {
02171 pgm->flagged = 0;
02172 pgm->unflagged = 1;
02173 }
02174 }
02175 pgm->undeleted = 1;
02176 pgm->deleted = 0;
02177
02178 vms_p->vmArrayIndex = 0;
02179 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02180 if (fold == 0 && urgent == 0)
02181 vms_p->newmessages = vms_p->vmArrayIndex;
02182 if (fold == 1)
02183 vms_p->oldmessages = vms_p->vmArrayIndex;
02184 if (fold == 0 && urgent == 1)
02185 vms_p->urgentmessages = vms_p->vmArrayIndex;
02186
02187 mail_free_searchpgm(&pgm);
02188 ast_mutex_unlock(&vms_p->lock);
02189 vms_p->updated = 0;
02190 return vms_p->vmArrayIndex;
02191 } else {
02192 ast_mutex_lock(&vms_p->lock);
02193 mail_ping(vms_p->mailstream);
02194 ast_mutex_unlock(&vms_p->lock);
02195 }
02196 return 0;
02197 }
02198
02199 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02200 {
02201
02202 check_quota(vms, vmu->imapfolder);
02203 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02204 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02205 ast_play_and_wait(chan, "vm-mailboxfull");
02206 return -1;
02207 }
02208
02209
02210 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));
02211 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02212 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02213 ast_play_and_wait(chan, "vm-mailboxfull");
02214 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02215 return -1;
02216 }
02217
02218 return 0;
02219 }
02220
02221
02222
02223
02224
02225
02226
02227
02228
02229
02230 static int messagecount(const char *context, const char *mailbox, const char *folder)
02231 {
02232 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02233 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02234 } else {
02235 return __messagecount(context, mailbox, folder);
02236 }
02237 }
02238
02239 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)
02240 {
02241 char *myserveremail = serveremail;
02242 char fn[PATH_MAX];
02243 char introfn[PATH_MAX];
02244 char mailbox[256];
02245 char *stringp;
02246 FILE *p = NULL;
02247 char tmp[80] = "/tmp/astmail-XXXXXX";
02248 long len;
02249 void *buf;
02250 int tempcopy = 0;
02251 STRING str;
02252 int ret;
02253 char *imap_flags = NIL;
02254 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02255 int box = NEW_FOLDER;
02256
02257
02258 if (msgnum < 0) {
02259 if(!imapgreetings) {
02260 return 0;
02261 } else {
02262 box = GREETINGS_FOLDER;
02263 }
02264 }
02265
02266 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02267 return -1;
02268 }
02269
02270
02271 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02272 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02273 imap_flags = "\\FLAGGED";
02274 }
02275
02276
02277 fmt = ast_strdupa(fmt);
02278 stringp = fmt;
02279 strsep(&stringp, "|");
02280
02281 if (!ast_strlen_zero(vmu->serveremail))
02282 myserveremail = vmu->serveremail;
02283
02284 if (msgnum > -1)
02285 make_file(fn, sizeof(fn), dir, msgnum);
02286 else
02287 ast_copy_string (fn, dir, sizeof(fn));
02288
02289 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02290 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02291 *introfn = '\0';
02292 }
02293
02294 if (ast_strlen_zero(vmu->email)) {
02295
02296
02297
02298
02299
02300 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02301 tempcopy = 1;
02302 }
02303
02304 if (!strcmp(fmt, "wav49"))
02305 fmt = "WAV";
02306 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02307
02308
02309
02310 if (!(p = vm_mkftemp(tmp))) {
02311 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02312 if (tempcopy)
02313 *(vmu->email) = '\0';
02314 return -1;
02315 }
02316
02317 if (msgnum < 0 && imapgreetings) {
02318 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02319 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02320 return -1;
02321 }
02322 imap_delete_old_greeting(fn, vms);
02323 }
02324
02325 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02326 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
02327 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
02328 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
02329
02330 len = ftell(p);
02331 rewind(p);
02332 if (!(buf = ast_malloc(len + 1))) {
02333 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02334 fclose(p);
02335 if (tempcopy)
02336 *(vmu->email) = '\0';
02337 return -1;
02338 }
02339 if (fread(buf, len, 1, p) < len) {
02340 if (ferror(p)) {
02341 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02342 return -1;
02343 }
02344 }
02345 ((char *) buf)[len] = '\0';
02346 INIT(&str, mail_string, buf, len);
02347 ret = init_mailstream(vms, box);
02348 if (ret == 0) {
02349 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
02350 ast_mutex_lock(&vms->lock);
02351 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02352 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02353 ast_mutex_unlock(&vms->lock);
02354 fclose(p);
02355 unlink(tmp);
02356 ast_free(buf);
02357 } else {
02358 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02359 fclose(p);
02360 unlink(tmp);
02361 ast_free(buf);
02362 return -1;
02363 }
02364 ast_debug(3, "%s stored\n", fn);
02365
02366 if (tempcopy)
02367 *(vmu->email) = '\0';
02368 inprocess_count(vmu->mailbox, vmu->context, -1);
02369 return 0;
02370
02371 }
02372
02373
02374
02375
02376
02377
02378
02379
02380
02381
02382
02383
02384
02385
02386 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02387 {
02388 char tmp[PATH_MAX] = "";
02389 char *mailboxnc;
02390 char *context;
02391 char *mb;
02392 char *cur;
02393 if (newmsgs)
02394 *newmsgs = 0;
02395 if (oldmsgs)
02396 *oldmsgs = 0;
02397 if (urgentmsgs)
02398 *urgentmsgs = 0;
02399
02400 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02401
02402 if (ast_strlen_zero(mailbox_context))
02403 return 0;
02404
02405 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02406 context = strchr(tmp, '@');
02407 if (strchr(mailbox_context, ',')) {
02408 int tmpnew, tmpold, tmpurgent;
02409 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02410 mb = tmp;
02411 while ((cur = strsep(&mb, ", "))) {
02412 if (!ast_strlen_zero(cur)) {
02413 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02414 return -1;
02415 else {
02416 if (newmsgs)
02417 *newmsgs += tmpnew;
02418 if (oldmsgs)
02419 *oldmsgs += tmpold;
02420 if (urgentmsgs)
02421 *urgentmsgs += tmpurgent;
02422 }
02423 }
02424 }
02425 return 0;
02426 }
02427 if (context) {
02428 *context = '\0';
02429 mailboxnc = tmp;
02430 context++;
02431 } else {
02432 context = "default";
02433 mailboxnc = (char *) mailbox_context;
02434 }
02435
02436 if (newmsgs) {
02437 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02438 if (!vmu) {
02439 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02440 return -1;
02441 }
02442 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02443 free_user(vmu);
02444 return -1;
02445 }
02446 free_user(vmu);
02447 }
02448 if (oldmsgs) {
02449 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02450 return -1;
02451 }
02452 }
02453 if (urgentmsgs) {
02454 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02455 return -1;
02456 }
02457 }
02458 return 0;
02459 }
02460
02461
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471 static int has_voicemail(const char *mailbox, const char *folder)
02472 {
02473 char tmp[256], *tmp2, *box, *context;
02474 ast_copy_string(tmp, mailbox, sizeof(tmp));
02475 tmp2 = tmp;
02476 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02477 while ((box = strsep(&tmp2, ",&"))) {
02478 if (!ast_strlen_zero(box)) {
02479 if (has_voicemail(box, folder)) {
02480 return 1;
02481 }
02482 }
02483 }
02484 }
02485 if ((context = strchr(tmp, '@'))) {
02486 *context++ = '\0';
02487 } else {
02488 context = "default";
02489 }
02490 return __messagecount(context, tmp, folder) ? 1 : 0;
02491 }
02492
02493
02494
02495
02496
02497
02498
02499
02500
02501
02502
02503
02504
02505
02506
02507
02508 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)
02509 {
02510 struct vm_state *sendvms = NULL, *destvms = NULL;
02511 char messagestring[10];
02512 if (msgnum >= recip->maxmsg) {
02513 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02514 return -1;
02515 }
02516 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02517 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02518 return -1;
02519 }
02520 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
02521 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02522 return -1;
02523 }
02524 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02525 ast_mutex_lock(&sendvms->lock);
02526 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02527 ast_mutex_unlock(&sendvms->lock);
02528 return 0;
02529 }
02530 ast_mutex_unlock(&sendvms->lock);
02531 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02532 return -1;
02533 }
02534
02535 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02536 {
02537 char tmp[256], *t = tmp;
02538 size_t left = sizeof(tmp);
02539
02540 if (box == OLD_FOLDER) {
02541 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02542 } else {
02543 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02544 }
02545
02546 if (box == NEW_FOLDER) {
02547 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02548 } else {
02549 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02550 }
02551
02552
02553 ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
02554
02555
02556 if (!ast_strlen_zero(authuser))
02557 ast_build_string(&t, &left, "/authuser=%s", authuser);
02558
02559
02560 if (!ast_strlen_zero(imapflags))
02561 ast_build_string(&t, &left, "/%s", imapflags);
02562
02563
02564 #if 1
02565 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02566 #else
02567 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02568 #endif
02569 if (box == NEW_FOLDER || box == OLD_FOLDER)
02570 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02571 else if (box == GREETINGS_FOLDER)
02572 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02573 else {
02574 if (!ast_strlen_zero(imapparentfolder)) {
02575
02576 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02577 } else {
02578 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02579 }
02580 }
02581 }
02582
02583 static int init_mailstream(struct vm_state *vms, int box)
02584 {
02585 MAILSTREAM *stream = NIL;
02586 long debug;
02587 char tmp[256];
02588
02589 if (!vms) {
02590 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02591 return -1;
02592 }
02593 if (option_debug > 2)
02594 ast_log(LOG_DEBUG, "vm_state user is:%s\n", vms->imapuser);
02595 if (vms->mailstream == NIL || !vms->mailstream) {
02596 if (option_debug)
02597 ast_log(LOG_DEBUG, "mailstream not set.\n");
02598 } else {
02599 stream = vms->mailstream;
02600 }
02601
02602 debug = NIL;
02603
02604 if (delimiter == '\0') {
02605 char *cp;
02606 #ifdef USE_SYSTEM_IMAP
02607 #include <imap/linkage.c>
02608 #elif defined(USE_SYSTEM_CCLIENT)
02609 #include <c-client/linkage.c>
02610 #else
02611 #include "linkage.c"
02612 #endif
02613
02614 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02615 ast_mutex_lock(&vms->lock);
02616 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02617 ast_mutex_unlock(&vms->lock);
02618 if (stream == NIL) {
02619 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02620 return -1;
02621 }
02622 get_mailbox_delimiter(stream);
02623
02624 for (cp = vms->imapfolder; *cp; cp++)
02625 if (*cp == '/')
02626 *cp = delimiter;
02627 }
02628
02629 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02630 if (option_debug > 2)
02631 ast_log(LOG_DEBUG, "Before mail_open, server: %s, box:%d\n", tmp, box);
02632 ast_mutex_lock(&vms->lock);
02633 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02634 ast_mutex_unlock(&vms->lock);
02635 if (vms->mailstream == NIL) {
02636 return -1;
02637 } else {
02638 return 0;
02639 }
02640 }
02641
02642 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02643 {
02644 SEARCHPGM *pgm;
02645 SEARCHHEADER *hdr;
02646 int ret, urgent = 0;
02647
02648
02649 if (box == 11) {
02650 box = NEW_FOLDER;
02651 urgent = 1;
02652 }
02653
02654 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02655 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02656 vms->imapversion = vmu->imapversion;
02657 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02658
02659 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
02660 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02661 return -1;
02662 }
02663
02664 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02665
02666
02667 if (box == 0) {
02668 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02669 check_quota(vms, (char *) mbox(vmu, box));
02670 }
02671
02672 ast_mutex_lock(&vms->lock);
02673 pgm = mail_newsearchpgm();
02674
02675
02676 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02677 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02678 pgm->header = hdr;
02679 pgm->deleted = 0;
02680 pgm->undeleted = 1;
02681
02682
02683 if (box == NEW_FOLDER && urgent == 1) {
02684 pgm->unseen = 1;
02685 pgm->seen = 0;
02686 pgm->flagged = 1;
02687 pgm->unflagged = 0;
02688 } else if (box == NEW_FOLDER && urgent == 0) {
02689 pgm->unseen = 1;
02690 pgm->seen = 0;
02691 pgm->flagged = 0;
02692 pgm->unflagged = 1;
02693 } else if (box == OLD_FOLDER) {
02694 pgm->seen = 1;
02695 pgm->unseen = 0;
02696 }
02697
02698 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02699
02700 vms->vmArrayIndex = 0;
02701 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02702 vms->lastmsg = vms->vmArrayIndex - 1;
02703 mail_free_searchpgm(&pgm);
02704
02705
02706
02707
02708 if (box == 0 && !vms->dh_arraysize) {
02709 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02710 }
02711 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02712 ast_mutex_unlock(&vms->lock);
02713 return -1;
02714 }
02715
02716 ast_mutex_unlock(&vms->lock);
02717 return 0;
02718 }
02719
02720 static void write_file(char *filename, char *buffer, unsigned long len)
02721 {
02722 FILE *output;
02723
02724 output = fopen (filename, "w");
02725 if (fwrite(buffer, len, 1, output) != 1) {
02726 if (ferror(output)) {
02727 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02728 }
02729 }
02730 fclose (output);
02731 }
02732
02733 static void update_messages_by_imapuser(const char *user, unsigned long number)
02734 {
02735 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02736
02737 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02738 return;
02739 }
02740
02741 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02742 vms->msgArray[vms->vmArrayIndex++] = number;
02743 }
02744
02745 void mm_searched(MAILSTREAM *stream, unsigned long number)
02746 {
02747 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02748
02749 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02750 return;
02751
02752 update_messages_by_imapuser(user, number);
02753 }
02754
02755 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02756 {
02757 struct ast_variable *var;
02758 struct ast_vm_user *vmu;
02759
02760 vmu = ast_calloc(1, sizeof *vmu);
02761 if (!vmu)
02762 return NULL;
02763
02764 populate_defaults(vmu);
02765 ast_set_flag(vmu, VM_ALLOCED);
02766
02767 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
02768 if (var) {
02769 apply_options_full(vmu, var);
02770 ast_variables_destroy(var);
02771 return vmu;
02772 } else {
02773 ast_free(vmu);
02774 return NULL;
02775 }
02776 }
02777
02778
02779
02780 void mm_exists(MAILSTREAM * stream, unsigned long number)
02781 {
02782
02783 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
02784 if (number == 0) return;
02785 set_update(stream);
02786 }
02787
02788
02789 void mm_expunged(MAILSTREAM * stream, unsigned long number)
02790 {
02791
02792 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
02793 if (number == 0) return;
02794 set_update(stream);
02795 }
02796
02797
02798 void mm_flags(MAILSTREAM * stream, unsigned long number)
02799 {
02800
02801 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
02802 if (number == 0) return;
02803 set_update(stream);
02804 }
02805
02806
02807 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
02808 {
02809 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
02810 mm_log (string, errflg);
02811 }
02812
02813
02814 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02815 {
02816 if (delimiter == '\0') {
02817 delimiter = delim;
02818 }
02819
02820 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02821 if (attributes & LATT_NOINFERIORS)
02822 ast_debug(5, "no inferiors\n");
02823 if (attributes & LATT_NOSELECT)
02824 ast_debug(5, "no select\n");
02825 if (attributes & LATT_MARKED)
02826 ast_debug(5, "marked\n");
02827 if (attributes & LATT_UNMARKED)
02828 ast_debug(5, "unmarked\n");
02829 }
02830
02831
02832 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
02833 {
02834 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
02835 if (attributes & LATT_NOINFERIORS)
02836 ast_debug(5, "no inferiors\n");
02837 if (attributes & LATT_NOSELECT)
02838 ast_debug(5, "no select\n");
02839 if (attributes & LATT_MARKED)
02840 ast_debug(5, "marked\n");
02841 if (attributes & LATT_UNMARKED)
02842 ast_debug(5, "unmarked\n");
02843 }
02844
02845
02846 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
02847 {
02848 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
02849 if (status->flags & SA_MESSAGES)
02850 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
02851 if (status->flags & SA_RECENT)
02852 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
02853 if (status->flags & SA_UNSEEN)
02854 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
02855 if (status->flags & SA_UIDVALIDITY)
02856 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
02857 if (status->flags & SA_UIDNEXT)
02858 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
02859 ast_log(AST_LOG_NOTICE, "\n");
02860 }
02861
02862
02863 void mm_log(char *string, long errflg)
02864 {
02865 switch ((short) errflg) {
02866 case NIL:
02867 ast_debug(1, "IMAP Info: %s\n", string);
02868 break;
02869 case PARSE:
02870 case WARN:
02871 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
02872 break;
02873 case ERROR:
02874 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
02875 break;
02876 }
02877 }
02878
02879
02880 void mm_dlog(char *string)
02881 {
02882 ast_log(AST_LOG_NOTICE, "%s\n", string);
02883 }
02884
02885
02886 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
02887 {
02888 struct ast_vm_user *vmu;
02889
02890 ast_debug(4, "Entering callback mm_login\n");
02891
02892 ast_copy_string(user, mb->user, MAILTMPLEN);
02893
02894
02895 if (!ast_strlen_zero(authpassword)) {
02896 ast_copy_string(pwd, authpassword, MAILTMPLEN);
02897 } else {
02898 AST_LIST_TRAVERSE(&users, vmu, list) {
02899 if (!strcasecmp(mb->user, vmu->imapuser)) {
02900 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02901 break;
02902 }
02903 }
02904 if (!vmu) {
02905 if ((vmu = find_user_realtime_imapuser(mb->user))) {
02906 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
02907 free_user(vmu);
02908 }
02909 }
02910 }
02911 }
02912
02913
02914 void mm_critical(MAILSTREAM * stream)
02915 {
02916 }
02917
02918
02919 void mm_nocritical(MAILSTREAM * stream)
02920 {
02921 }
02922
02923
02924 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
02925 {
02926 kill (getpid (), SIGSTOP);
02927 return NIL;
02928 }
02929
02930
02931 void mm_fatal(char *string)
02932 {
02933 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
02934 }
02935
02936
02937 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
02938 {
02939 struct vm_state *vms;
02940 char *mailbox = stream->mailbox, *user;
02941 char buf[1024] = "";
02942 unsigned long usage = 0, limit = 0;
02943
02944 while (pquota) {
02945 usage = pquota->usage;
02946 limit = pquota->limit;
02947 pquota = pquota->next;
02948 }
02949
02950 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)))) {
02951 ast_log(AST_LOG_ERROR, "No state found.\n");
02952 return;
02953 }
02954
02955 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
02956
02957 vms->quota_usage = usage;
02958 vms->quota_limit = limit;
02959 }
02960
02961 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
02962 {
02963 char *start, *eol_pnt;
02964 int taglen;
02965
02966 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
02967 return NULL;
02968
02969 taglen = strlen(tag) + 1;
02970 if (taglen < 1)
02971 return NULL;
02972
02973 if (!(start = strstr(header, tag)))
02974 return NULL;
02975
02976
02977 memset(buf, 0, len);
02978
02979 ast_copy_string(buf, start+taglen, len);
02980 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
02981 *eol_pnt = '\0';
02982 return buf;
02983 }
02984
02985 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
02986 {
02987 char *start, *quote, *eol_pnt;
02988
02989 if (ast_strlen_zero(mailbox))
02990 return NULL;
02991
02992 if (!(start = strstr(mailbox, "/user=")))
02993 return NULL;
02994
02995 ast_copy_string(buf, start+6, len);
02996
02997 if (!(quote = strchr(buf, '\"'))) {
02998 if (!(eol_pnt = strchr(buf, '/')))
02999 eol_pnt = strchr(buf,'}');
03000 *eol_pnt = '\0';
03001 return buf;
03002 } else {
03003 eol_pnt = strchr(buf+1,'\"');
03004 *eol_pnt = '\0';
03005 return buf+1;
03006 }
03007 }
03008
03009 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
03010 {
03011 struct vm_state *vms_p;
03012
03013 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03014 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
03015 return vms_p;
03016 }
03017 if (option_debug > 4)
03018 ast_log(AST_LOG_DEBUG, "Adding new vmstate for %s\n", vmu->imapuser);
03019 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
03020 return NULL;
03021 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
03022 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
03023 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
03024 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
03025 vms_p->mailstream = NIL;
03026 vms_p->imapversion = vmu->imapversion;
03027 if (option_debug > 4)
03028 ast_log(AST_LOG_DEBUG, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
03029 vms_p->updated = 1;
03030
03031 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
03032 init_vm_state(vms_p);
03033 vmstate_insert(vms_p);
03034 return vms_p;
03035 }
03036
03037 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
03038 {
03039 struct vmstate *vlist = NULL;
03040
03041 if (interactive) {
03042 struct vm_state *vms;
03043 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03044 vms = pthread_getspecific(ts_vmstate.key);
03045 return vms;
03046 }
03047
03048 AST_LIST_LOCK(&vmstates);
03049 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03050 if (!vlist->vms) {
03051 ast_debug(3, "error: vms is NULL for %s\n", user);
03052 continue;
03053 }
03054 if (vlist->vms->imapversion != imapversion) {
03055 continue;
03056 }
03057 if (!vlist->vms->imapuser) {
03058 ast_debug(3, "error: imapuser is NULL for %s\n", user);
03059 continue;
03060 }
03061
03062 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
03063 AST_LIST_UNLOCK(&vmstates);
03064 return vlist->vms;
03065 }
03066 }
03067 AST_LIST_UNLOCK(&vmstates);
03068
03069 ast_debug(3, "%s not found in vmstates\n", user);
03070
03071 return NULL;
03072 }
03073
03074 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
03075 {
03076
03077 struct vmstate *vlist = NULL;
03078 const char *local_context = S_OR(context, "default");
03079
03080 if (interactive) {
03081 struct vm_state *vms;
03082 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03083 vms = pthread_getspecific(ts_vmstate.key);
03084 return vms;
03085 }
03086
03087 AST_LIST_LOCK(&vmstates);
03088 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03089 if (!vlist->vms) {
03090 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03091 continue;
03092 }
03093 if (vlist->vms->imapversion != imapversion) {
03094 continue;
03095 }
03096 if (!vlist->vms->username || !vlist->vms->context) {
03097 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03098 continue;
03099 }
03100
03101 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);
03102
03103 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03104 ast_debug(3, "Found it!\n");
03105 AST_LIST_UNLOCK(&vmstates);
03106 return vlist->vms;
03107 }
03108 }
03109 AST_LIST_UNLOCK(&vmstates);
03110
03111 ast_debug(3, "%s not found in vmstates\n", mailbox);
03112
03113 return NULL;
03114 }
03115
03116 static void vmstate_insert(struct vm_state *vms)
03117 {
03118 struct vmstate *v;
03119 struct vm_state *altvms;
03120
03121
03122
03123
03124 if (vms->interactive == 1) {
03125 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03126 if (altvms) {
03127 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03128 vms->newmessages = altvms->newmessages;
03129 vms->oldmessages = altvms->oldmessages;
03130 vms->vmArrayIndex = altvms->vmArrayIndex;
03131 vms->lastmsg = altvms->lastmsg;
03132 vms->curmsg = altvms->curmsg;
03133
03134 vms->persist_vms = altvms;
03135
03136 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03137 vms->mailstream = altvms->mailstream;
03138 #else
03139 vms->mailstream = NIL;
03140 #endif
03141 }
03142 return;
03143 }
03144
03145 if (!(v = ast_calloc(1, sizeof(*v))))
03146 return;
03147
03148 v->vms = vms;
03149
03150 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03151
03152 AST_LIST_LOCK(&vmstates);
03153 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03154 AST_LIST_UNLOCK(&vmstates);
03155 }
03156
03157 static void vmstate_delete(struct vm_state *vms)
03158 {
03159 struct vmstate *vc = NULL;
03160 struct vm_state *altvms = NULL;
03161
03162
03163
03164 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03165 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03166 altvms->newmessages = vms->newmessages;
03167 altvms->oldmessages = vms->oldmessages;
03168 altvms->updated = 1;
03169 vms->mailstream = mail_close(vms->mailstream);
03170
03171
03172 return;
03173 }
03174
03175 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03176
03177 AST_LIST_LOCK(&vmstates);
03178 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03179 if (vc->vms == vms) {
03180 AST_LIST_REMOVE_CURRENT(list);
03181 break;
03182 }
03183 }
03184 AST_LIST_TRAVERSE_SAFE_END
03185 AST_LIST_UNLOCK(&vmstates);
03186
03187 if (vc) {
03188 ast_mutex_destroy(&vc->vms->lock);
03189 ast_free(vc);
03190 }
03191 else
03192 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03193 }
03194
03195 static void set_update(MAILSTREAM * stream)
03196 {
03197 struct vm_state *vms;
03198 char *mailbox = stream->mailbox, *user;
03199 char buf[1024] = "";
03200
03201 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03202 if (user && option_debug > 2)
03203 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03204 return;
03205 }
03206
03207 ast_debug(3, "User %s mailbox set for update.\n", user);
03208
03209 vms->updated = 1;
03210 }
03211
03212 static void init_vm_state(struct vm_state *vms)
03213 {
03214 int x;
03215 vms->vmArrayIndex = 0;
03216 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
03217 vms->msgArray[x] = 0;
03218 }
03219 ast_mutex_init(&vms->lock);
03220 }
03221
03222 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03223 {
03224 char *body_content;
03225 char *body_decoded;
03226 char *fn = is_intro ? vms->introfn : vms->fn;
03227 unsigned long len;
03228 unsigned long newlen;
03229 char filename[256];
03230
03231 if (!body || body == NIL)
03232 return -1;
03233
03234 ast_mutex_lock(&vms->lock);
03235 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03236 ast_mutex_unlock(&vms->lock);
03237 if (body_content != NIL) {
03238 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03239
03240 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03241
03242 if (!newlen) {
03243 return -1;
03244 }
03245 write_file(filename, (char *) body_decoded, newlen);
03246 } else {
03247 ast_debug(5, "Body of message is NULL.\n");
03248 return -1;
03249 }
03250 return 0;
03251 }
03252
03253
03254
03255
03256
03257
03258
03259
03260 static void get_mailbox_delimiter(MAILSTREAM *stream) {
03261 char tmp[50];
03262 snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
03263 mail_list(stream, tmp, "*");
03264 }
03265
03266
03267
03268
03269
03270
03271
03272
03273 static void check_quota(struct vm_state *vms, char *mailbox) {
03274 ast_mutex_lock(&vms->lock);
03275 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03276 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03277 if (vms && vms->mailstream != NULL) {
03278 imap_getquotaroot(vms->mailstream, mailbox);
03279 } else {
03280 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03281 }
03282 ast_mutex_unlock(&vms->lock);
03283 }
03284
03285 #endif
03286
03287
03288
03289
03290
03291 static int vm_lock_path(const char *path)
03292 {
03293 switch (ast_lock_path(path)) {
03294 case AST_LOCK_TIMEOUT:
03295 return -1;
03296 default:
03297 return 0;
03298 }
03299 }
03300
03301
03302 #ifdef ODBC_STORAGE
03303 struct generic_prepare_struct {
03304 char *sql;
03305 int argc;
03306 char **argv;
03307 };
03308
03309 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03310 {
03311 struct generic_prepare_struct *gps = data;
03312 int res, i;
03313 SQLHSTMT stmt;
03314
03315 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03316 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03317 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03318 return NULL;
03319 }
03320 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03321 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03322 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03323 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03324 return NULL;
03325 }
03326 for (i = 0; i < gps->argc; i++)
03327 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03328
03329 return stmt;
03330 }
03331
03332
03333
03334
03335
03336
03337
03338
03339
03340
03341
03342
03343
03344
03345
03346 static int retrieve_file(char *dir, int msgnum)
03347 {
03348 int x = 0;
03349 int res;
03350 int fd = -1;
03351 size_t fdlen = 0;
03352 void *fdm = MAP_FAILED;
03353 SQLSMALLINT colcount = 0;
03354 SQLHSTMT stmt;
03355 char sql[PATH_MAX];
03356 char fmt[80]="";
03357 char *c;
03358 char coltitle[256];
03359 SQLSMALLINT collen;
03360 SQLSMALLINT datatype;
03361 SQLSMALLINT decimaldigits;
03362 SQLSMALLINT nullable;
03363 SQLULEN colsize;
03364 SQLLEN colsize2;
03365 FILE *f = NULL;
03366 char rowdata[80];
03367 char fn[PATH_MAX];
03368 char full_fn[PATH_MAX];
03369 char msgnums[80];
03370 char *argv[] = { dir, msgnums };
03371 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03372
03373 struct odbc_obj *obj;
03374 obj = ast_odbc_request_obj(odbc_database, 0);
03375 if (obj) {
03376 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03377 c = strchr(fmt, '|');
03378 if (c)
03379 *c = '\0';
03380 if (!strcasecmp(fmt, "wav49"))
03381 strcpy(fmt, "WAV");
03382 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03383 if (msgnum > -1)
03384 make_file(fn, sizeof(fn), dir, msgnum);
03385 else
03386 ast_copy_string(fn, dir, sizeof(fn));
03387
03388
03389 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03390
03391 if (!(f = fopen(full_fn, "w+"))) {
03392 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03393 goto yuck;
03394 }
03395
03396 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03397 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03398 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03399 if (!stmt) {
03400 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03401 ast_odbc_release_obj(obj);
03402 goto yuck;
03403 }
03404 res = SQLFetch(stmt);
03405 if (res == SQL_NO_DATA) {
03406 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03407 ast_odbc_release_obj(obj);
03408 goto yuck;
03409 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03410 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03411 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03412 ast_odbc_release_obj(obj);
03413 goto yuck;
03414 }
03415 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03416 if (fd < 0) {
03417 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03418 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03419 ast_odbc_release_obj(obj);
03420 goto yuck;
03421 }
03422 res = SQLNumResultCols(stmt, &colcount);
03423 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03424 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03425 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03426 ast_odbc_release_obj(obj);
03427 goto yuck;
03428 }
03429 if (f)
03430 fprintf(f, "[message]\n");
03431 for (x = 0; x < colcount; x++) {
03432 rowdata[0] = '\0';
03433 colsize = 0;
03434 collen = sizeof(coltitle);
03435 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03436 &datatype, &colsize, &decimaldigits, &nullable);
03437 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03438 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03439 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03440 ast_odbc_release_obj(obj);
03441 goto yuck;
03442 }
03443 if (!strcasecmp(coltitle, "recording")) {
03444 off_t offset;
03445 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03446 fdlen = colsize2;
03447 if (fd > -1) {
03448 char tmp[1]="";
03449 lseek(fd, fdlen - 1, SEEK_SET);
03450 if (write(fd, tmp, 1) != 1) {
03451 close(fd);
03452 fd = -1;
03453 continue;
03454 }
03455
03456 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03457 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03458 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03459 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03460 ast_odbc_release_obj(obj);
03461 goto yuck;
03462 } else {
03463 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03464 munmap(fdm, CHUNKSIZE);
03465 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03466 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03467 unlink(full_fn);
03468 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03469 ast_odbc_release_obj(obj);
03470 goto yuck;
03471 }
03472 }
03473 }
03474 if (truncate(full_fn, fdlen) < 0) {
03475 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03476 }
03477 }
03478 } else {
03479 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03480 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03481 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03482 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03483 ast_odbc_release_obj(obj);
03484 goto yuck;
03485 }
03486 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03487 fprintf(f, "%s=%s\n", coltitle, rowdata);
03488 }
03489 }
03490 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03491 ast_odbc_release_obj(obj);
03492 } else
03493 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03494 yuck:
03495 if (f)
03496 fclose(f);
03497 if (fd > -1)
03498 close(fd);
03499 return x - 1;
03500 }
03501
03502
03503
03504
03505
03506
03507
03508
03509
03510
03511
03512
03513 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03514 {
03515 int x = 0;
03516 int res;
03517 SQLHSTMT stmt;
03518 char sql[PATH_MAX];
03519 char rowdata[20];
03520 char *argv[] = { dir };
03521 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03522
03523 struct odbc_obj *obj;
03524 obj = ast_odbc_request_obj(odbc_database, 0);
03525 if (obj) {
03526 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
03527
03528 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03529 if (!stmt) {
03530 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03531 ast_odbc_release_obj(obj);
03532 goto yuck;
03533 }
03534 res = SQLFetch(stmt);
03535 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03536 if (res == SQL_NO_DATA) {
03537 ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
03538 } else {
03539 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03540 }
03541
03542 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03543 ast_odbc_release_obj(obj);
03544 goto yuck;
03545 }
03546 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03547 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03548 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03549 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03550 ast_odbc_release_obj(obj);
03551 goto yuck;
03552 }
03553 if (sscanf(rowdata, "%30d", &x) != 1)
03554 ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
03555 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03556 ast_odbc_release_obj(obj);
03557 return x;
03558 } else
03559 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03560 yuck:
03561 return x - 1;
03562 }
03563
03564
03565
03566
03567
03568
03569
03570
03571
03572
03573 static int message_exists(char *dir, int msgnum)
03574 {
03575 int x = 0;
03576 int res;
03577 SQLHSTMT stmt;
03578 char sql[PATH_MAX];
03579 char rowdata[20];
03580 char msgnums[20];
03581 char *argv[] = { dir, msgnums };
03582 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03583
03584 struct odbc_obj *obj;
03585 obj = ast_odbc_request_obj(odbc_database, 0);
03586 if (obj) {
03587 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03588 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03589 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03590 if (!stmt) {
03591 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03592 ast_odbc_release_obj(obj);
03593 goto yuck;
03594 }
03595 res = SQLFetch(stmt);
03596 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03597 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03598 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03599 ast_odbc_release_obj(obj);
03600 goto yuck;
03601 }
03602 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03603 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03604 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03605 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03606 ast_odbc_release_obj(obj);
03607 goto yuck;
03608 }
03609 if (sscanf(rowdata, "%30d", &x) != 1)
03610 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03611 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03612 ast_odbc_release_obj(obj);
03613 } else
03614 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03615 yuck:
03616 return x;
03617 }
03618
03619
03620
03621
03622
03623
03624
03625
03626
03627
03628 static int count_messages(struct ast_vm_user *vmu, char *dir)
03629 {
03630 int x = 0;
03631 int res;
03632 SQLHSTMT stmt;
03633 char sql[PATH_MAX];
03634 char rowdata[20];
03635 char *argv[] = { dir };
03636 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03637
03638 struct odbc_obj *obj;
03639 obj = ast_odbc_request_obj(odbc_database, 0);
03640 if (obj) {
03641 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03642 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03643 if (!stmt) {
03644 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03645 ast_odbc_release_obj(obj);
03646 goto yuck;
03647 }
03648 res = SQLFetch(stmt);
03649 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03650 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03651 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03652 ast_odbc_release_obj(obj);
03653 goto yuck;
03654 }
03655 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03656 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03657 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03658 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03659 ast_odbc_release_obj(obj);
03660 goto yuck;
03661 }
03662 if (sscanf(rowdata, "%30d", &x) != 1)
03663 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03664 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03665 ast_odbc_release_obj(obj);
03666 return x;
03667 } else
03668 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03669 yuck:
03670 return x - 1;
03671
03672 }
03673
03674
03675
03676
03677
03678
03679
03680
03681
03682
03683
03684 static void delete_file(const char *sdir, int smsg)
03685 {
03686 SQLHSTMT stmt;
03687 char sql[PATH_MAX];
03688 char msgnums[20];
03689 char *argv[] = { NULL, msgnums };
03690 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03691 struct odbc_obj *obj;
03692
03693 argv[0] = ast_strdupa(sdir);
03694
03695 obj = ast_odbc_request_obj(odbc_database, 0);
03696 if (obj) {
03697 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03698 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03699 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03700 if (!stmt)
03701 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03702 else
03703 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03704 ast_odbc_release_obj(obj);
03705 } else
03706 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03707 return;
03708 }
03709
03710
03711
03712
03713
03714
03715
03716
03717
03718
03719
03720
03721 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
03722 {
03723 SQLHSTMT stmt;
03724 char sql[512];
03725 char msgnums[20];
03726 char msgnumd[20];
03727 struct odbc_obj *obj;
03728 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
03729 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03730
03731 delete_file(ddir, dmsg);
03732 obj = ast_odbc_request_obj(odbc_database, 0);
03733 if (obj) {
03734 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03735 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03736 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);
03737 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03738 if (!stmt)
03739 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
03740 else
03741 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03742 ast_odbc_release_obj(obj);
03743 } else
03744 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03745 return;
03746 }
03747
03748 struct insert_data {
03749 char *sql;
03750 const char *dir;
03751 const char *msgnums;
03752 void *data;
03753 SQLLEN datalen;
03754 SQLLEN indlen;
03755 const char *context;
03756 const char *macrocontext;
03757 const char *callerid;
03758 const char *origtime;
03759 const char *duration;
03760 const char *mailboxuser;
03761 const char *mailboxcontext;
03762 const char *category;
03763 const char *flag;
03764 };
03765
03766 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
03767 {
03768 struct insert_data *data = vdata;
03769 int res;
03770 SQLHSTMT stmt;
03771
03772 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03773 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03774 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03775 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03776 return NULL;
03777 }
03778
03779 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
03780 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
03781 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
03782 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
03783 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
03784 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
03785 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
03786 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
03787 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
03788 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
03789 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
03790 if (!ast_strlen_zero(data->category)) {
03791 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
03792 }
03793 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
03794 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03795 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
03796 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03797 return NULL;
03798 }
03799
03800 return stmt;
03801 }
03802
03803
03804
03805
03806
03807
03808
03809
03810
03811
03812
03813
03814
03815
03816 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
03817 {
03818 int res = 0;
03819 int fd = -1;
03820 void *fdm = MAP_FAILED;
03821 off_t fdlen = -1;
03822 SQLHSTMT stmt;
03823 char sql[PATH_MAX];
03824 char msgnums[20];
03825 char fn[PATH_MAX];
03826 char full_fn[PATH_MAX];
03827 char fmt[80]="";
03828 char *c;
03829 struct ast_config *cfg = NULL;
03830 struct odbc_obj *obj;
03831 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
03832 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "" };
03833 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
03834
03835 delete_file(dir, msgnum);
03836 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
03837 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03838 return -1;
03839 }
03840
03841 do {
03842 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03843 c = strchr(fmt, '|');
03844 if (c)
03845 *c = '\0';
03846 if (!strcasecmp(fmt, "wav49"))
03847 strcpy(fmt, "WAV");
03848 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03849 if (msgnum > -1)
03850 make_file(fn, sizeof(fn), dir, msgnum);
03851 else
03852 ast_copy_string(fn, dir, sizeof(fn));
03853 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03854 cfg = ast_config_load(full_fn, config_flags);
03855 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03856 fd = open(full_fn, O_RDWR);
03857 if (fd < 0) {
03858 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
03859 res = -1;
03860 break;
03861 }
03862 if (valid_config(cfg)) {
03863 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
03864 idata.context = "";
03865 }
03866 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
03867 idata.macrocontext = "";
03868 }
03869 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
03870 idata.callerid = "";
03871 }
03872 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
03873 idata.origtime = "";
03874 }
03875 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
03876 idata.duration = "";
03877 }
03878 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
03879 idata.category = "";
03880 }
03881 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
03882 idata.flag = "";
03883 }
03884 }
03885 fdlen = lseek(fd, 0, SEEK_END);
03886 if (fdlen < 0 || lseek(fd, 0, SEEK_SET) < 0) {
03887 ast_log(AST_LOG_WARNING, "Failed to process sound file '%s': %s\n", full_fn, strerror(errno));
03888 res = -1;
03889 break;
03890 }
03891 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
03892 if (fdm == MAP_FAILED) {
03893 ast_log(AST_LOG_WARNING, "Memory map failed for sound file '%s'!\n", full_fn);
03894 res = -1;
03895 break;
03896 }
03897 idata.data = fdm;
03898 idata.datalen = idata.indlen = fdlen;
03899
03900 if (!ast_strlen_zero(idata.category))
03901 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03902 else
03903 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
03904
03905 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
03906 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03907 } else {
03908 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03909 res = -1;
03910 }
03911 } while (0);
03912 if (obj) {
03913 ast_odbc_release_obj(obj);
03914 }
03915 if (valid_config(cfg))
03916 ast_config_destroy(cfg);
03917 if (fdm != MAP_FAILED)
03918 munmap(fdm, fdlen);
03919 if (fd > -1)
03920 close(fd);
03921 return res;
03922 }
03923
03924
03925
03926
03927
03928
03929
03930
03931
03932
03933
03934
03935
03936
03937 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
03938 {
03939 SQLHSTMT stmt;
03940 char sql[PATH_MAX];
03941 char msgnums[20];
03942 char msgnumd[20];
03943 struct odbc_obj *obj;
03944 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
03945 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
03946
03947 delete_file(ddir, dmsg);
03948 obj = ast_odbc_request_obj(odbc_database, 0);
03949 if (obj) {
03950 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03951 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
03952 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
03953 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03954 if (!stmt)
03955 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03956 else
03957 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03958 ast_odbc_release_obj(obj);
03959 } else
03960 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03961 return;
03962 }
03963
03964
03965
03966
03967
03968
03969
03970
03971
03972
03973
03974
03975 static int remove_file(char *dir, int msgnum)
03976 {
03977 char fn[PATH_MAX];
03978 char full_fn[PATH_MAX];
03979 char msgnums[80];
03980
03981 if (msgnum > -1) {
03982 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03983 make_file(fn, sizeof(fn), dir, msgnum);
03984 } else
03985 ast_copy_string(fn, dir, sizeof(fn));
03986 ast_filedelete(fn, NULL);
03987 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03988 unlink(full_fn);
03989 return 0;
03990 }
03991 #else
03992 #ifndef IMAP_STORAGE
03993
03994
03995
03996
03997
03998
03999
04000
04001
04002 static int count_messages(struct ast_vm_user *vmu, char *dir)
04003 {
04004
04005 int vmcount = 0;
04006 DIR *vmdir = NULL;
04007 struct dirent *vment = NULL;
04008
04009 if (vm_lock_path(dir))
04010 return ERROR_LOCK_PATH;
04011
04012 if ((vmdir = opendir(dir))) {
04013 while ((vment = readdir(vmdir))) {
04014 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
04015 vmcount++;
04016 }
04017 }
04018 closedir(vmdir);
04019 }
04020 ast_unlock_path(dir);
04021
04022 return vmcount;
04023 }
04024
04025
04026
04027
04028
04029
04030
04031
04032 static void rename_file(char *sfn, char *dfn)
04033 {
04034 char stxt[PATH_MAX];
04035 char dtxt[PATH_MAX];
04036 ast_filerename(sfn, dfn, NULL);
04037 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
04038 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
04039 if (ast_check_realtime("voicemail_data")) {
04040 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
04041 }
04042 rename(stxt, dtxt);
04043 }
04044
04045
04046
04047
04048
04049
04050
04051
04052
04053
04054
04055
04056 static int last_message_index(struct ast_vm_user *vmu, char *dir)
04057 {
04058 int x;
04059 unsigned char map[MAXMSGLIMIT] = "";
04060 DIR *msgdir;
04061 struct dirent *msgdirent;
04062 int msgdirint;
04063 char extension[4];
04064 int stopcount = 0;
04065
04066
04067
04068
04069
04070 if (!(msgdir = opendir(dir))) {
04071 return -1;
04072 }
04073
04074 while ((msgdirent = readdir(msgdir))) {
04075 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
04076 map[msgdirint] = 1;
04077 stopcount++;
04078 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
04079 }
04080 }
04081 closedir(msgdir);
04082
04083 for (x = 0; x < vmu->maxmsg; x++) {
04084 if (map[x] == 1) {
04085 stopcount--;
04086 } else if (map[x] == 0 && !stopcount) {
04087 break;
04088 }
04089 }
04090
04091 return x - 1;
04092 }
04093
04094 #endif
04095 #endif
04096 #ifndef IMAP_STORAGE
04097
04098
04099
04100
04101
04102
04103
04104
04105
04106
04107 static int copy(char *infile, char *outfile)
04108 {
04109 int ifd;
04110 int ofd;
04111 int res;
04112 int len;
04113 char buf[4096];
04114
04115 #ifdef HARDLINK_WHEN_POSSIBLE
04116
04117 if (link(infile, outfile)) {
04118 #endif
04119 if ((ifd = open(infile, O_RDONLY)) < 0) {
04120 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
04121 return -1;
04122 }
04123 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
04124 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
04125 close(ifd);
04126 return -1;
04127 }
04128 do {
04129 len = read(ifd, buf, sizeof(buf));
04130 if (len < 0) {
04131 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
04132 close(ifd);
04133 close(ofd);
04134 unlink(outfile);
04135 } else if (len) {
04136 res = write(ofd, buf, len);
04137 if (errno == ENOMEM || errno == ENOSPC || res != len) {
04138 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
04139 close(ifd);
04140 close(ofd);
04141 unlink(outfile);
04142 }
04143 }
04144 } while (len);
04145 close(ifd);
04146 close(ofd);
04147 return 0;
04148 #ifdef HARDLINK_WHEN_POSSIBLE
04149 } else {
04150
04151 return 0;
04152 }
04153 #endif
04154 }
04155
04156
04157
04158
04159
04160
04161
04162
04163
04164
04165 static void copy_plain_file(char *frompath, char *topath)
04166 {
04167 char frompath2[PATH_MAX], topath2[PATH_MAX];
04168 struct ast_variable *tmp,*var = NULL;
04169 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04170 ast_filecopy(frompath, topath, NULL);
04171 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04172 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04173 if (ast_check_realtime("voicemail_data")) {
04174 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04175
04176 for (tmp = var; tmp; tmp = tmp->next) {
04177 if (!strcasecmp(tmp->name, "origmailbox")) {
04178 origmailbox = tmp->value;
04179 } else if (!strcasecmp(tmp->name, "context")) {
04180 context = tmp->value;
04181 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04182 macrocontext = tmp->value;
04183 } else if (!strcasecmp(tmp->name, "exten")) {
04184 exten = tmp->value;
04185 } else if (!strcasecmp(tmp->name, "priority")) {
04186 priority = tmp->value;
04187 } else if (!strcasecmp(tmp->name, "callerchan")) {
04188 callerchan = tmp->value;
04189 } else if (!strcasecmp(tmp->name, "callerid")) {
04190 callerid = tmp->value;
04191 } else if (!strcasecmp(tmp->name, "origdate")) {
04192 origdate = tmp->value;
04193 } else if (!strcasecmp(tmp->name, "origtime")) {
04194 origtime = tmp->value;
04195 } else if (!strcasecmp(tmp->name, "category")) {
04196 category = tmp->value;
04197 } else if (!strcasecmp(tmp->name, "duration")) {
04198 duration = tmp->value;
04199 }
04200 }
04201 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);
04202 }
04203 copy(frompath2, topath2);
04204 ast_variables_destroy(var);
04205 }
04206 #endif
04207
04208
04209
04210
04211
04212
04213
04214
04215
04216 static int vm_delete(char *file)
04217 {
04218 char *txt;
04219 int txtsize = 0;
04220
04221 txtsize = (strlen(file) + 5)*sizeof(char);
04222 txt = ast_alloca(txtsize);
04223
04224
04225
04226 if (ast_check_realtime("voicemail_data")) {
04227 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04228 }
04229 snprintf(txt, txtsize, "%s.txt", file);
04230 unlink(txt);
04231 return ast_filedelete(file, NULL);
04232 }
04233
04234
04235
04236
04237 static int inbuf(struct baseio *bio, FILE *fi)
04238 {
04239 int l;
04240
04241 if (bio->ateof)
04242 return 0;
04243
04244 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04245 if (ferror(fi))
04246 return -1;
04247
04248 bio->ateof = 1;
04249 return 0;
04250 }
04251
04252 bio->iolen = l;
04253 bio->iocp = 0;
04254
04255 return 1;
04256 }
04257
04258
04259
04260
04261 static int inchar(struct baseio *bio, FILE *fi)
04262 {
04263 if (bio->iocp>=bio->iolen) {
04264 if (!inbuf(bio, fi))
04265 return EOF;
04266 }
04267
04268 return bio->iobuf[bio->iocp++];
04269 }
04270
04271
04272
04273
04274 static int ochar(struct baseio *bio, int c, FILE *so)
04275 {
04276 if (bio->linelength >= BASELINELEN) {
04277 if (fputs(ENDL, so) == EOF) {
04278 return -1;
04279 }
04280
04281 bio->linelength = 0;
04282 }
04283
04284 if (putc(((unsigned char) c), so) == EOF) {
04285 return -1;
04286 }
04287
04288 bio->linelength++;
04289
04290 return 1;
04291 }
04292
04293
04294
04295
04296
04297
04298
04299
04300
04301
04302 static int base_encode(char *filename, FILE *so)
04303 {
04304 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04305 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04306 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04307 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04308 int i, hiteof = 0;
04309 FILE *fi;
04310 struct baseio bio;
04311
04312 memset(&bio, 0, sizeof(bio));
04313 bio.iocp = BASEMAXINLINE;
04314
04315 if (!(fi = fopen(filename, "rb"))) {
04316 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04317 return -1;
04318 }
04319
04320 while (!hiteof){
04321 unsigned char igroup[3], ogroup[4];
04322 int c, n;
04323
04324 memset(igroup, 0, sizeof(igroup));
04325
04326 for (n = 0; n < 3; n++) {
04327 if ((c = inchar(&bio, fi)) == EOF) {
04328 hiteof = 1;
04329 break;
04330 }
04331
04332 igroup[n] = (unsigned char) c;
04333 }
04334
04335 if (n > 0) {
04336 ogroup[0]= dtable[igroup[0] >> 2];
04337 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04338 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04339 ogroup[3]= dtable[igroup[2] & 0x3F];
04340
04341 if (n < 3) {
04342 ogroup[3] = '=';
04343
04344 if (n < 2)
04345 ogroup[2] = '=';
04346 }
04347
04348 for (i = 0; i < 4; i++)
04349 ochar(&bio, ogroup[i], so);
04350 }
04351 }
04352
04353 fclose(fi);
04354
04355 if (fputs(ENDL, so) == EOF) {
04356 return 0;
04357 }
04358
04359 return 1;
04360 }
04361
04362 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)
04363 {
04364 char callerid[256];
04365 char num[12];
04366 char fromdir[256], fromfile[256];
04367 struct ast_config *msg_cfg;
04368 const char *origcallerid, *origtime;
04369 char origcidname[80], origcidnum[80], origdate[80];
04370 int inttime;
04371 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04372
04373
04374 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04375 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04376 snprintf(num, sizeof(num), "%d", msgnum);
04377 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04378 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04379 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04380 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04381 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04382 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04383 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04384 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04385 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04386 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04387
04388
04389 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04390 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04391 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04392 strcat(fromfile, ".txt");
04393 }
04394 if (!(msg_cfg = ast_config_load(fromfile, config_flags)) || !(valid_config(msg_cfg))) {
04395 if (option_debug > 0) {
04396 ast_log(LOG_DEBUG, "Config load for message text file '%s' failed\n", fromfile);
04397 }
04398 return;
04399 }
04400
04401 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04402 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04403 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04404 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04405 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04406 }
04407
04408 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04409 struct timeval tv = { inttime, };
04410 struct ast_tm tm;
04411 ast_localtime(&tv, &tm, NULL);
04412 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04413 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04414 }
04415 ast_config_destroy(msg_cfg);
04416 }
04417
04418
04419
04420
04421
04422
04423
04424
04425
04426 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04427 {
04428 const char *ptr;
04429
04430
04431 ast_str_set(buf, maxlen, "\"");
04432 for (ptr = from; *ptr; ptr++) {
04433 if (*ptr == '"' || *ptr == '\\') {
04434 ast_str_append(buf, maxlen, "\\%c", *ptr);
04435 } else {
04436 ast_str_append(buf, maxlen, "%c", *ptr);
04437 }
04438 }
04439 ast_str_append(buf, maxlen, "\"");
04440
04441 return ast_str_buffer(*buf);
04442 }
04443
04444
04445
04446
04447
04448 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04449 {
04450 const struct vm_zone *z = NULL;
04451 struct timeval t = ast_tvnow();
04452
04453
04454 if (!ast_strlen_zero(vmu->zonetag)) {
04455
04456 AST_LIST_LOCK(&zones);
04457 AST_LIST_TRAVERSE(&zones, z, list) {
04458 if (!strcmp(z->name, vmu->zonetag))
04459 break;
04460 }
04461 AST_LIST_UNLOCK(&zones);
04462 }
04463 ast_localtime(&t, tm, z ? z->timezone : NULL);
04464 return tm;
04465 }
04466
04467
04468
04469
04470
04471 static int check_mime(const char *str)
04472 {
04473 for (; *str; str++) {
04474 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04475 return 1;
04476 }
04477 }
04478 return 0;
04479 }
04480
04481
04482
04483
04484
04485
04486
04487
04488
04489
04490
04491
04492
04493
04494
04495
04496
04497
04498 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04499 {
04500 struct ast_str *tmp = ast_str_alloca(80);
04501 int first_section = 1;
04502
04503 ast_str_reset(*end);
04504 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04505 for (; *start; start++) {
04506 int need_encoding = 0;
04507 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04508 need_encoding = 1;
04509 }
04510 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04511 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04512 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04513 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04514
04515 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04516 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04517 first_section = 0;
04518 }
04519 if (need_encoding && *start == ' ') {
04520 ast_str_append(&tmp, -1, "_");
04521 } else if (need_encoding) {
04522 ast_str_append(&tmp, -1, "=%hhX", *start);
04523 } else {
04524 ast_str_append(&tmp, -1, "%c", *start);
04525 }
04526 }
04527 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04528 return ast_str_buffer(*end);
04529 }
04530
04531
04532
04533
04534
04535
04536
04537
04538
04539
04540
04541
04542
04543
04544
04545
04546
04547
04548
04549
04550
04551
04552
04553
04554 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)
04555 {
04556 char date[256];
04557 char host[MAXHOSTNAMELEN] = "";
04558 char who[256];
04559 char bound[256];
04560 char dur[256];
04561 struct ast_tm tm;
04562 char enc_cidnum[256] = "", enc_cidname[256] = "";
04563 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04564 char *greeting_attachment;
04565 char filename[256];
04566
04567 if (!str1 || !str2) {
04568 ast_free(str1);
04569 ast_free(str2);
04570 return;
04571 }
04572
04573 if (cidnum) {
04574 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04575 }
04576 if (cidname) {
04577 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04578 }
04579 gethostname(host, sizeof(host) - 1);
04580
04581 if (strchr(srcemail, '@')) {
04582 ast_copy_string(who, srcemail, sizeof(who));
04583 } else {
04584 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04585 }
04586
04587 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04588 if (greeting_attachment) {
04589 *greeting_attachment++ = '\0';
04590 }
04591
04592 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04593 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04594 fprintf(p, "Date: %s" ENDL, date);
04595
04596
04597 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04598
04599 if (!ast_strlen_zero(fromstring)) {
04600 struct ast_channel *ast;
04601 if ((ast = ast_dummy_channel_alloc())) {
04602 char *ptr;
04603 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04604 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04605
04606 if (check_mime(ast_str_buffer(str1))) {
04607 int first_line = 1;
04608 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04609 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04610 *ptr = '\0';
04611 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04612 first_line = 0;
04613
04614 ast_str_set(&str2, 0, "%s", ptr + 1);
04615 }
04616 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04617 } else {
04618 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04619 }
04620 ast = ast_channel_unref(ast);
04621 } else {
04622 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04623 }
04624 } else {
04625 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04626 }
04627
04628 if (check_mime(vmu->fullname)) {
04629 int first_line = 1;
04630 char *ptr;
04631 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04632 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04633 *ptr = '\0';
04634 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04635 first_line = 0;
04636
04637 ast_str_set(&str2, 0, "%s", ptr + 1);
04638 }
04639 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04640 } else {
04641 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04642 }
04643
04644 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04645 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04646 struct ast_channel *ast;
04647 if ((ast = ast_dummy_channel_alloc())) {
04648 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04649 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04650 if (check_mime(ast_str_buffer(str1))) {
04651 int first_line = 1;
04652 char *ptr;
04653 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04654 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04655 *ptr = '\0';
04656 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04657 first_line = 0;
04658
04659 ast_str_set(&str2, 0, "%s", ptr + 1);
04660 }
04661 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04662 } else {
04663 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04664 }
04665 ast = ast_channel_unref(ast);
04666 } else {
04667 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04668 }
04669 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04670 if (ast_strlen_zero(flag)) {
04671 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04672 } else {
04673 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04674 }
04675 } else {
04676 if (ast_strlen_zero(flag)) {
04677 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04678 } else {
04679 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04680 }
04681 }
04682
04683 fprintf(p, "Message-ID: <Asterisk-%d-%u-%s-%d@%s>" ENDL, msgnum + 1,
04684 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04685 if (imap) {
04686
04687 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04688
04689 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
04690 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
04691 #ifdef IMAP_STORAGE
04692 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
04693 #else
04694 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
04695 #endif
04696
04697 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
04698 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan->priority);
04699 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan->name);
04700 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
04701 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
04702 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
04703 if (!ast_strlen_zero(category)) {
04704 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
04705 } else {
04706 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
04707 }
04708 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
04709 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
04710 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
04711 }
04712 if (!ast_strlen_zero(cidnum)) {
04713 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
04714 }
04715 if (!ast_strlen_zero(cidname)) {
04716 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
04717 }
04718 fprintf(p, "MIME-Version: 1.0" ENDL);
04719 if (attach_user_voicemail) {
04720
04721 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%u", msgnum + 1, mailbox,
04722 (int) getpid(), (unsigned int) ast_random());
04723
04724 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
04725 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
04726 fprintf(p, "--%s" ENDL, bound);
04727 }
04728 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
04729 if (emailbody || vmu->emailbody) {
04730 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
04731 struct ast_channel *ast;
04732 if ((ast = ast_dummy_channel_alloc())) {
04733 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04734 ast_str_substitute_variables(&str1, 0, ast, e_body);
04735 #ifdef IMAP_STORAGE
04736 {
04737
04738 char *line = ast_str_buffer(str1), *next;
04739 do {
04740
04741 if ((next = strchr(line, '\n'))) {
04742 *next++ = '\0';
04743 }
04744 fprintf(p, "%s" ENDL, line);
04745 line = next;
04746 } while (!ast_strlen_zero(line));
04747 }
04748 #else
04749 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
04750 #endif
04751 ast = ast_channel_unref(ast);
04752 } else {
04753 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04754 }
04755 } else if (msgnum > -1) {
04756 if (strcmp(vmu->mailbox, mailbox)) {
04757
04758 struct ast_config *msg_cfg;
04759 const char *v;
04760 int inttime;
04761 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
04762 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04763
04764 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04765 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
04766 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04767 strcat(fromfile, ".txt");
04768 }
04769 if ((msg_cfg = ast_config_load(fromfile, config_flags)) && valid_config(msg_cfg)) {
04770 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04771 ast_copy_string(origcallerid, v, sizeof(origcallerid));
04772 }
04773
04774
04775
04776 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
04777 struct timeval tv = { inttime, };
04778 struct ast_tm tm;
04779 ast_localtime(&tv, &tm, NULL);
04780 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04781 }
04782 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
04783 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
04784 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
04785 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
04786 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
04787 date, origcallerid, origdate);
04788 ast_config_destroy(msg_cfg);
04789 } else {
04790 goto plain_message;
04791 }
04792 } else {
04793 plain_message:
04794 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
04795 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
04796 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
04797 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
04798 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
04799 }
04800 } else {
04801 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
04802 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
04803 }
04804
04805 if (imap || attach_user_voicemail) {
04806 if (!ast_strlen_zero(attach2)) {
04807 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04808 ast_debug(5, "creating second attachment filename %s\n", filename);
04809 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
04810 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
04811 ast_debug(5, "creating attachment filename %s\n", filename);
04812 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04813 } else {
04814 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
04815 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
04816 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
04817 }
04818 }
04819 ast_free(str1);
04820 ast_free(str2);
04821 }
04822
04823 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)
04824 {
04825 char tmpdir[256], newtmp[256];
04826 char fname[256];
04827 char tmpcmd[256];
04828 int tmpfd = -1;
04829 int soxstatus = 0;
04830
04831
04832 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
04833
04834 if (vmu->volgain < -.001 || vmu->volgain > .001) {
04835 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
04836 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
04837 tmpfd = mkstemp(newtmp);
04838 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
04839 ast_debug(3, "newtmp: %s\n", newtmp);
04840 if (tmpfd > -1) {
04841 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
04842 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
04843 attach = newtmp;
04844 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
04845 } else {
04846 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
04847 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
04848 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
04849 }
04850 }
04851 }
04852 fprintf(p, "--%s" ENDL, bound);
04853 if (msgnum > -1)
04854 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
04855 else
04856 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
04857 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
04858 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
04859 if (msgnum > -1)
04860 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
04861 else
04862 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
04863 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
04864 base_encode(fname, p);
04865 if (last)
04866 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
04867 if (tmpfd > -1) {
04868 if (soxstatus == 0) {
04869 unlink(fname);
04870 }
04871 close(tmpfd);
04872 unlink(newtmp);
04873 }
04874 return 0;
04875 }
04876
04877 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)
04878 {
04879 FILE *p = NULL;
04880 char tmp[80] = "/tmp/astmail-XXXXXX";
04881 char tmp2[256];
04882 char *stringp;
04883
04884 if (vmu && ast_strlen_zero(vmu->email)) {
04885 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
04886 return(0);
04887 }
04888
04889
04890 format = ast_strdupa(format);
04891 stringp = format;
04892 strsep(&stringp, "|");
04893
04894 if (!strcmp(format, "wav49"))
04895 format = "WAV";
04896 ast_debug(3, "Attaching file '%s', format '%s', uservm is '%d', global is %u\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
04897
04898
04899 if ((p = vm_mkftemp(tmp)) == NULL) {
04900 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04901 return -1;
04902 } else {
04903 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
04904 fclose(p);
04905 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
04906 ast_safe_system(tmp2);
04907 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
04908 }
04909 return 0;
04910 }
04911
04912 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)
04913 {
04914 char enc_cidnum[256], enc_cidname[256];
04915 char date[256];
04916 char host[MAXHOSTNAMELEN] = "";
04917 char who[256];
04918 char dur[PATH_MAX];
04919 char tmp[80] = "/tmp/astmail-XXXXXX";
04920 char tmp2[PATH_MAX];
04921 struct ast_tm tm;
04922 FILE *p;
04923 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04924
04925 if (!str1 || !str2) {
04926 ast_free(str1);
04927 ast_free(str2);
04928 return -1;
04929 }
04930
04931 if (cidnum) {
04932 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04933 }
04934 if (cidname) {
04935 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04936 }
04937
04938 if ((p = vm_mkftemp(tmp)) == NULL) {
04939 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
04940 ast_free(str1);
04941 ast_free(str2);
04942 return -1;
04943 }
04944 gethostname(host, sizeof(host)-1);
04945 if (strchr(srcemail, '@')) {
04946 ast_copy_string(who, srcemail, sizeof(who));
04947 } else {
04948 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04949 }
04950 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04951 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04952 fprintf(p, "Date: %s\n", date);
04953
04954
04955 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
04956
04957 if (!ast_strlen_zero(pagerfromstring)) {
04958 struct ast_channel *ast;
04959 if ((ast = ast_dummy_channel_alloc())) {
04960 char *ptr;
04961 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04962 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
04963
04964 if (check_mime(ast_str_buffer(str1))) {
04965 int first_line = 1;
04966 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04967 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04968 *ptr = '\0';
04969 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04970 first_line = 0;
04971
04972 ast_str_set(&str2, 0, "%s", ptr + 1);
04973 }
04974 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04975 } else {
04976 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04977 }
04978 ast = ast_channel_unref(ast);
04979 } else {
04980 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04981 }
04982 } else {
04983 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04984 }
04985
04986 if (check_mime(vmu->fullname)) {
04987 int first_line = 1;
04988 char *ptr;
04989 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
04990 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04991 *ptr = '\0';
04992 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04993 first_line = 0;
04994
04995 ast_str_set(&str2, 0, "%s", ptr + 1);
04996 }
04997 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
04998 } else {
04999 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
05000 }
05001
05002 if (!ast_strlen_zero(pagersubject)) {
05003 struct ast_channel *ast;
05004 if ((ast = ast_dummy_channel_alloc())) {
05005 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05006 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
05007 if (check_mime(ast_str_buffer(str1))) {
05008 int first_line = 1;
05009 char *ptr;
05010 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
05011 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
05012 *ptr = '\0';
05013 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05014 first_line = 0;
05015
05016 ast_str_set(&str2, 0, "%s", ptr + 1);
05017 }
05018 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05019 } else {
05020 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
05021 }
05022 ast = ast_channel_unref(ast);
05023 } else {
05024 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05025 }
05026 } else {
05027 if (ast_strlen_zero(flag)) {
05028 fprintf(p, "Subject: New VM\n\n");
05029 } else {
05030 fprintf(p, "Subject: New %s VM\n\n", flag);
05031 }
05032 }
05033
05034 if (pagerbody) {
05035 struct ast_channel *ast;
05036 if ((ast = ast_dummy_channel_alloc())) {
05037 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05038 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
05039 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
05040 ast = ast_channel_unref(ast);
05041 } else {
05042 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05043 }
05044 } else {
05045 fprintf(p, "New %s long %s msg in box %s\n"
05046 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
05047 }
05048
05049 fclose(p);
05050 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
05051 ast_safe_system(tmp2);
05052 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
05053 ast_free(str1);
05054 ast_free(str2);
05055 return 0;
05056 }
05057
05058
05059
05060
05061
05062
05063
05064
05065
05066
05067 static int get_date(char *s, int len)
05068 {
05069 struct ast_tm tm;
05070 struct timeval t = ast_tvnow();
05071
05072 ast_localtime(&t, &tm, "UTC");
05073
05074 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
05075 }
05076
05077 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
05078 {
05079 int res;
05080 char fn[PATH_MAX];
05081 char dest[PATH_MAX];
05082
05083 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
05084
05085 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
05086 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
05087 return -1;
05088 }
05089
05090 RETRIEVE(fn, -1, ext, context);
05091 if (ast_fileexists(fn, NULL, NULL) > 0) {
05092 res = ast_stream_and_wait(chan, fn, ecodes);
05093 if (res) {
05094 DISPOSE(fn, -1);
05095 return res;
05096 }
05097 } else {
05098
05099 DISPOSE(fn, -1);
05100 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
05101 if (res)
05102 return res;
05103 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
05104 if (res)
05105 return res;
05106 }
05107 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
05108 return res;
05109 }
05110
05111 static void free_zone(struct vm_zone *z)
05112 {
05113 ast_free(z);
05114 }
05115
05116 #ifdef ODBC_STORAGE
05117 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05118 {
05119 int x = -1;
05120 int res;
05121 SQLHSTMT stmt = NULL;
05122 char sql[PATH_MAX];
05123 char rowdata[20];
05124 char tmp[PATH_MAX] = "";
05125 struct odbc_obj *obj = NULL;
05126 char *context;
05127 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05128
05129 if (newmsgs)
05130 *newmsgs = 0;
05131 if (oldmsgs)
05132 *oldmsgs = 0;
05133 if (urgentmsgs)
05134 *urgentmsgs = 0;
05135
05136
05137 if (ast_strlen_zero(mailbox))
05138 return 0;
05139
05140 ast_copy_string(tmp, mailbox, sizeof(tmp));
05141
05142 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
05143 int u, n, o;
05144 char *next, *remaining = tmp;
05145 while ((next = strsep(&remaining, " ,"))) {
05146 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05147 return -1;
05148 }
05149 if (urgentmsgs) {
05150 *urgentmsgs += u;
05151 }
05152 if (newmsgs) {
05153 *newmsgs += n;
05154 }
05155 if (oldmsgs) {
05156 *oldmsgs += o;
05157 }
05158 }
05159 return 0;
05160 }
05161
05162 context = strchr(tmp, '@');
05163 if (context) {
05164 *context = '\0';
05165 context++;
05166 } else
05167 context = "default";
05168
05169 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05170 do {
05171 if (newmsgs) {
05172 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05173 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05174 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05175 break;
05176 }
05177 res = SQLFetch(stmt);
05178 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05179 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05180 break;
05181 }
05182 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05183 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05184 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05185 break;
05186 }
05187 *newmsgs = atoi(rowdata);
05188 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05189 }
05190
05191 if (oldmsgs) {
05192 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05193 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05194 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05195 break;
05196 }
05197 res = SQLFetch(stmt);
05198 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05199 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05200 break;
05201 }
05202 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05203 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05204 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05205 break;
05206 }
05207 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05208 *oldmsgs = atoi(rowdata);
05209 }
05210
05211 if (urgentmsgs) {
05212 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05213 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05214 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05215 break;
05216 }
05217 res = SQLFetch(stmt);
05218 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05219 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05220 break;
05221 }
05222 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05223 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05224 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05225 break;
05226 }
05227 *urgentmsgs = atoi(rowdata);
05228 }
05229
05230 x = 0;
05231 } while (0);
05232 } else {
05233 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05234 }
05235
05236 if (stmt) {
05237 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05238 }
05239 if (obj) {
05240 ast_odbc_release_obj(obj);
05241 }
05242 return x;
05243 }
05244
05245
05246
05247
05248
05249
05250
05251
05252
05253
05254 static int messagecount(const char *context, const char *mailbox, const char *folder)
05255 {
05256 struct odbc_obj *obj = NULL;
05257 int nummsgs = 0;
05258 int res;
05259 SQLHSTMT stmt = NULL;
05260 char sql[PATH_MAX];
05261 char rowdata[20];
05262 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05263 if (!folder)
05264 folder = "INBOX";
05265
05266 if (ast_strlen_zero(mailbox))
05267 return 0;
05268
05269 obj = ast_odbc_request_obj(odbc_database, 0);
05270 if (obj) {
05271 if (!strcmp(folder, "INBOX")) {
05272 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);
05273 } else {
05274 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05275 }
05276 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05277 if (!stmt) {
05278 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05279 goto yuck;
05280 }
05281 res = SQLFetch(stmt);
05282 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05283 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05284 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05285 goto yuck;
05286 }
05287 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05288 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05289 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05290 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05291 goto yuck;
05292 }
05293 nummsgs = atoi(rowdata);
05294 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05295 } else
05296 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05297
05298 yuck:
05299 if (obj)
05300 ast_odbc_release_obj(obj);
05301 return nummsgs;
05302 }
05303
05304
05305
05306
05307
05308
05309
05310
05311
05312 static int has_voicemail(const char *mailbox, const char *folder)
05313 {
05314 char tmp[256], *tmp2 = tmp, *box, *context;
05315 ast_copy_string(tmp, mailbox, sizeof(tmp));
05316 while ((context = box = strsep(&tmp2, ",&"))) {
05317 strsep(&context, "@");
05318 if (ast_strlen_zero(context))
05319 context = "default";
05320 if (messagecount(context, box, folder))
05321 return 1;
05322 }
05323 return 0;
05324 }
05325 #endif
05326 #ifndef IMAP_STORAGE
05327
05328
05329
05330
05331
05332
05333
05334
05335
05336
05337
05338
05339
05340
05341
05342
05343 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)
05344 {
05345 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05346 const char *frombox = mbox(vmu, imbox);
05347 const char *userfolder;
05348 int recipmsgnum;
05349 int res = 0;
05350
05351 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05352
05353 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05354 userfolder = "Urgent";
05355 } else {
05356 userfolder = "INBOX";
05357 }
05358
05359 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05360
05361 if (!dir)
05362 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05363 else
05364 ast_copy_string(fromdir, dir, sizeof(fromdir));
05365
05366 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05367 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05368
05369 if (vm_lock_path(todir))
05370 return ERROR_LOCK_PATH;
05371
05372 recipmsgnum = last_message_index(recip, todir) + 1;
05373 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05374 make_file(topath, sizeof(topath), todir, recipmsgnum);
05375 #ifndef ODBC_STORAGE
05376 if (EXISTS(fromdir, msgnum, frompath, chan->language)) {
05377 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05378 } else {
05379 #endif
05380
05381
05382
05383 copy_plain_file(frompath, topath);
05384 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
05385 vm_delete(topath);
05386 #ifndef ODBC_STORAGE
05387 }
05388 #endif
05389 } else {
05390 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05391 res = -1;
05392 }
05393 ast_unlock_path(todir);
05394 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05395 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05396 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05397 flag);
05398
05399 return res;
05400 }
05401 #endif
05402 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05403
05404 static int messagecount(const char *context, const char *mailbox, const char *folder)
05405 {
05406 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05407 }
05408
05409 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05410 {
05411 DIR *dir;
05412 struct dirent *de;
05413 char fn[256];
05414 int ret = 0;
05415
05416
05417 if (ast_strlen_zero(mailbox))
05418 return 0;
05419
05420 if (ast_strlen_zero(folder))
05421 folder = "INBOX";
05422 if (ast_strlen_zero(context))
05423 context = "default";
05424
05425 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05426
05427 if (!(dir = opendir(fn)))
05428 return 0;
05429
05430 while ((de = readdir(dir))) {
05431 if (!strncasecmp(de->d_name, "msg", 3)) {
05432 if (shortcircuit) {
05433 ret = 1;
05434 break;
05435 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05436 ret++;
05437 }
05438 }
05439 }
05440
05441 closedir(dir);
05442
05443 return ret;
05444 }
05445
05446
05447
05448
05449
05450
05451
05452
05453
05454
05455 static int has_voicemail(const char *mailbox, const char *folder)
05456 {
05457 char tmp[256], *tmp2 = tmp, *box, *context;
05458 ast_copy_string(tmp, mailbox, sizeof(tmp));
05459 if (ast_strlen_zero(folder)) {
05460 folder = "INBOX";
05461 }
05462 while ((box = strsep(&tmp2, ",&"))) {
05463 if ((context = strchr(box, '@')))
05464 *context++ = '\0';
05465 else
05466 context = "default";
05467 if (__has_voicemail(context, box, folder, 1))
05468 return 1;
05469
05470 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05471 return 1;
05472 }
05473 }
05474 return 0;
05475 }
05476
05477
05478 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05479 {
05480 char tmp[256];
05481 char *context;
05482
05483
05484 if (ast_strlen_zero(mailbox))
05485 return 0;
05486
05487 if (newmsgs)
05488 *newmsgs = 0;
05489 if (oldmsgs)
05490 *oldmsgs = 0;
05491 if (urgentmsgs)
05492 *urgentmsgs = 0;
05493
05494 if (strchr(mailbox, ',')) {
05495 int tmpnew, tmpold, tmpurgent;
05496 char *mb, *cur;
05497
05498 ast_copy_string(tmp, mailbox, sizeof(tmp));
05499 mb = tmp;
05500 while ((cur = strsep(&mb, ", "))) {
05501 if (!ast_strlen_zero(cur)) {
05502 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05503 return -1;
05504 else {
05505 if (newmsgs)
05506 *newmsgs += tmpnew;
05507 if (oldmsgs)
05508 *oldmsgs += tmpold;
05509 if (urgentmsgs)
05510 *urgentmsgs += tmpurgent;
05511 }
05512 }
05513 }
05514 return 0;
05515 }
05516
05517 ast_copy_string(tmp, mailbox, sizeof(tmp));
05518
05519 if ((context = strchr(tmp, '@')))
05520 *context++ = '\0';
05521 else
05522 context = "default";
05523
05524 if (newmsgs)
05525 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05526 if (oldmsgs)
05527 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05528 if (urgentmsgs)
05529 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05530
05531 return 0;
05532 }
05533
05534 #endif
05535
05536
05537 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05538 {
05539 int urgentmsgs = 0;
05540 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05541 if (newmsgs) {
05542 *newmsgs += urgentmsgs;
05543 }
05544 return res;
05545 }
05546
05547 static void run_externnotify(char *context, char *extension, const char *flag)
05548 {
05549 char arguments[255];
05550 char ext_context[256] = "";
05551 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05552 struct ast_smdi_mwi_message *mwi_msg;
05553
05554 if (!ast_strlen_zero(context))
05555 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05556 else
05557 ast_copy_string(ext_context, extension, sizeof(ext_context));
05558
05559 if (smdi_iface) {
05560 if (ast_app_has_voicemail(ext_context, NULL))
05561 ast_smdi_mwi_set(smdi_iface, extension);
05562 else
05563 ast_smdi_mwi_unset(smdi_iface, extension);
05564
05565 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05566 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05567 if (!strncmp(mwi_msg->cause, "INV", 3))
05568 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05569 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05570 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05571 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05572 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05573 } else {
05574 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05575 }
05576 }
05577
05578 if (!ast_strlen_zero(externnotify)) {
05579 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05580 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05581 } else {
05582 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &",
05583 externnotify, S_OR(context, "\"\""),
05584 extension, newvoicemails,
05585 oldvoicemails, urgentvoicemails);
05586 ast_debug(1, "Executing %s\n", arguments);
05587 ast_safe_system(arguments);
05588 }
05589 }
05590 }
05591
05592
05593
05594
05595
05596
05597 struct leave_vm_options {
05598 unsigned int flags;
05599 signed char record_gain;
05600 char *exitcontext;
05601 };
05602
05603
05604
05605
05606
05607
05608
05609
05610
05611
05612
05613 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
05614 {
05615 #ifdef IMAP_STORAGE
05616 int newmsgs, oldmsgs;
05617 #else
05618 char urgdir[PATH_MAX];
05619 #endif
05620 char txtfile[PATH_MAX];
05621 char tmptxtfile[PATH_MAX];
05622 struct vm_state *vms = NULL;
05623 char callerid[256];
05624 FILE *txt;
05625 char date[256];
05626 int txtdes;
05627 int res = 0;
05628 int msgnum;
05629 int duration = 0;
05630 int sound_duration = 0;
05631 int ausemacro = 0;
05632 int ousemacro = 0;
05633 int ouseexten = 0;
05634 char tmpdur[16];
05635 char priority[16];
05636 char origtime[16];
05637 char dir[PATH_MAX];
05638 char tmpdir[PATH_MAX];
05639 char fn[PATH_MAX];
05640 char prefile[PATH_MAX] = "";
05641 char tempfile[PATH_MAX] = "";
05642 char ext_context[256] = "";
05643 char fmt[80];
05644 char *context;
05645 char ecodes[17] = "#";
05646 struct ast_str *tmp = ast_str_create(16);
05647 char *tmpptr;
05648 struct ast_vm_user *vmu;
05649 struct ast_vm_user svm;
05650 const char *category = NULL;
05651 const char *code;
05652 const char *alldtmf = "0123456789ABCD*#";
05653 char flag[80];
05654
05655 if (!tmp) {
05656 return -1;
05657 }
05658
05659 ast_str_set(&tmp, 0, "%s", ext);
05660 ext = ast_str_buffer(tmp);
05661 if ((context = strchr(ext, '@'))) {
05662 *context++ = '\0';
05663 tmpptr = strchr(context, '&');
05664 } else {
05665 tmpptr = strchr(ext, '&');
05666 }
05667
05668 if (tmpptr)
05669 *tmpptr++ = '\0';
05670
05671 ast_channel_lock(chan);
05672 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
05673 category = ast_strdupa(category);
05674 }
05675 ast_channel_unlock(chan);
05676
05677 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
05678 ast_copy_string(flag, "Urgent", sizeof(flag));
05679 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
05680 ast_copy_string(flag, "PRIORITY", sizeof(flag));
05681 } else {
05682 flag[0] = '\0';
05683 }
05684
05685 ast_debug(3, "Before find_user\n");
05686 if (!(vmu = find_user(&svm, context, ext))) {
05687 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
05688 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05689 ast_free(tmp);
05690 return res;
05691 }
05692
05693 if (strcmp(vmu->context, "default"))
05694 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
05695 else
05696 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
05697
05698
05699
05700
05701
05702
05703 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
05704 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
05705 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
05706 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
05707 }
05708
05709
05710
05711
05712 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
05713 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
05714 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
05715 ast_free(tmp);
05716 return -1;
05717 }
05718 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
05719 if (ast_fileexists(tempfile, NULL, NULL) > 0)
05720 ast_copy_string(prefile, tempfile, sizeof(prefile));
05721
05722 DISPOSE(tempfile, -1);
05723
05724 #ifndef IMAP_STORAGE
05725 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
05726 #else
05727 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
05728 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
05729 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
05730 }
05731 #endif
05732
05733
05734 if (ast_test_flag(vmu, VM_OPERATOR)) {
05735 if (!ast_strlen_zero(vmu->exit)) {
05736 if (ast_exists_extension(chan, vmu->exit, "o", 1,
05737 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05738 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05739 ouseexten = 1;
05740 }
05741 } else if (ast_exists_extension(chan, chan->context, "o", 1,
05742 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05743 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05744 ouseexten = 1;
05745 } else if (!ast_strlen_zero(chan->macrocontext)
05746 && ast_exists_extension(chan, chan->macrocontext, "o", 1,
05747 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05748 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
05749 ousemacro = 1;
05750 }
05751 }
05752
05753 if (!ast_strlen_zero(vmu->exit)) {
05754 if (ast_exists_extension(chan, vmu->exit, "a", 1,
05755 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05756 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05757 }
05758 } else if (ast_exists_extension(chan, chan->context, "a", 1,
05759 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05760 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05761 } else if (!ast_strlen_zero(chan->macrocontext)
05762 && ast_exists_extension(chan, chan->macrocontext, "a", 1,
05763 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05764 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
05765 ausemacro = 1;
05766 }
05767
05768 if (ast_test_flag(options, OPT_DTMFEXIT)) {
05769 for (code = alldtmf; *code; code++) {
05770 char e[2] = "";
05771 e[0] = *code;
05772 if (strchr(ecodes, e[0]) == NULL
05773 && ast_canmatch_extension(chan,
05774 (!ast_strlen_zero(options->exitcontext) ? options->exitcontext : chan->context),
05775 e, 1, S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
05776 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
05777 }
05778 }
05779 }
05780
05781
05782 if (!ast_strlen_zero(prefile)) {
05783 #ifdef ODBC_STORAGE
05784 int success =
05785 #endif
05786 RETRIEVE(prefile, -1, ext, context);
05787 if (ast_fileexists(prefile, NULL, NULL) > 0) {
05788 if (ast_streamfile(chan, prefile, chan->language) > -1)
05789 res = ast_waitstream(chan, ecodes);
05790 #ifdef ODBC_STORAGE
05791 if (success == -1) {
05792
05793 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
05794 store_file(prefile, vmu->mailbox, vmu->context, -1);
05795 }
05796 #endif
05797 } else {
05798 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
05799 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
05800 }
05801 DISPOSE(prefile, -1);
05802 if (res < 0) {
05803 ast_debug(1, "Hang up during prefile playback\n");
05804 free_user(vmu);
05805 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05806 ast_free(tmp);
05807 return -1;
05808 }
05809 }
05810 if (res == '#') {
05811
05812 ast_set_flag(options, OPT_SILENT);
05813 res = 0;
05814 }
05815
05816 if (vmu->maxmsg == 0) {
05817 if (option_debug > 2)
05818 ast_log(LOG_DEBUG, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
05819 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
05820 goto leave_vm_out;
05821 }
05822 if (!res && !ast_test_flag(options, OPT_SILENT)) {
05823 res = ast_stream_and_wait(chan, INTRO, ecodes);
05824 if (res == '#') {
05825 ast_set_flag(options, OPT_SILENT);
05826 res = 0;
05827 }
05828 }
05829 if (res > 0)
05830 ast_stopstream(chan);
05831
05832
05833 if (res == '*') {
05834 chan->exten[0] = 'a';
05835 chan->exten[1] = '\0';
05836 if (!ast_strlen_zero(vmu->exit)) {
05837 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05838 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
05839 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05840 }
05841 chan->priority = 0;
05842 free_user(vmu);
05843 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05844 ast_free(tmp);
05845 return 0;
05846 }
05847
05848
05849 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
05850 transfer:
05851 if (ouseexten || ousemacro) {
05852 chan->exten[0] = 'o';
05853 chan->exten[1] = '\0';
05854 if (!ast_strlen_zero(vmu->exit)) {
05855 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
05856 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
05857 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
05858 }
05859 ast_play_and_wait(chan, "transfer");
05860 chan->priority = 0;
05861 free_user(vmu);
05862 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05863 }
05864 ast_free(tmp);
05865 return OPERATOR_EXIT;
05866 }
05867
05868
05869 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
05870 if (!ast_strlen_zero(options->exitcontext)) {
05871 ast_copy_string(chan->context, options->exitcontext, sizeof(chan->context));
05872 }
05873 free_user(vmu);
05874 ast_free(tmp);
05875 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
05876 return res;
05877 }
05878
05879 if (res < 0) {
05880 free_user(vmu);
05881 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05882 ast_free(tmp);
05883 return -1;
05884 }
05885
05886 ast_copy_string(fmt, vmfmts, sizeof(fmt));
05887 if (!ast_strlen_zero(fmt)) {
05888 msgnum = 0;
05889
05890 #ifdef IMAP_STORAGE
05891
05892
05893 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
05894 if (res < 0) {
05895 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
05896 ast_free(tmp);
05897 return -1;
05898 }
05899 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
05900
05901
05902
05903
05904 if (!(vms = create_vm_state_from_user(vmu))) {
05905 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
05906 ast_free(tmp);
05907 return -1;
05908 }
05909 }
05910 vms->newmessages++;
05911
05912
05913 msgnum = newmsgs + oldmsgs;
05914 ast_debug(3, "Messagecount set to %d\n", msgnum);
05915 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
05916
05917 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
05918
05919 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
05920 goto leave_vm_out;
05921 }
05922 #else
05923 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
05924 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05925 if (!res)
05926 res = ast_waitstream(chan, "");
05927 ast_log(AST_LOG_WARNING, "No more messages possible\n");
05928 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05929 inprocess_count(vmu->mailbox, vmu->context, -1);
05930 goto leave_vm_out;
05931 }
05932
05933 #endif
05934 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
05935 txtdes = mkstemp(tmptxtfile);
05936 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
05937 if (txtdes < 0) {
05938 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
05939 if (!res)
05940 res = ast_waitstream(chan, "");
05941 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
05942 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
05943 inprocess_count(vmu->mailbox, vmu->context, -1);
05944 goto leave_vm_out;
05945 }
05946
05947
05948 if (res >= 0) {
05949
05950 res = ast_stream_and_wait(chan, "beep", "");
05951 }
05952
05953
05954 if (ast_check_realtime("voicemail_data")) {
05955 snprintf(priority, sizeof(priority), "%d", chan->priority);
05956 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
05957 get_date(date, sizeof(date));
05958 ast_callerid_merge(callerid, sizeof(callerid),
05959 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05960 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05961 "Unknown");
05962 ast_store_realtime("voicemail_data",
05963 "origmailbox", ext,
05964 "context", chan->context,
05965 "macrocontext", chan->macrocontext,
05966 "exten", chan->exten,
05967 "priority", priority,
05968 "callerchan", chan->name,
05969 "callerid", callerid,
05970 "origdate", date,
05971 "origtime", origtime,
05972 "category", S_OR(category, ""),
05973 "filename", tmptxtfile,
05974 SENTINEL);
05975 }
05976
05977
05978 txt = fdopen(txtdes, "w+");
05979 if (txt) {
05980 get_date(date, sizeof(date));
05981 ast_callerid_merge(callerid, sizeof(callerid),
05982 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
05983 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
05984 "Unknown");
05985 fprintf(txt,
05986 ";\n"
05987 "; Message Information file\n"
05988 ";\n"
05989 "[message]\n"
05990 "origmailbox=%s\n"
05991 "context=%s\n"
05992 "macrocontext=%s\n"
05993 "exten=%s\n"
05994 "rdnis=%s\n"
05995 "priority=%d\n"
05996 "callerchan=%s\n"
05997 "callerid=%s\n"
05998 "origdate=%s\n"
05999 "origtime=%ld\n"
06000 "category=%s\n",
06001 ext,
06002 chan->context,
06003 chan->macrocontext,
06004 chan->exten,
06005 S_COR(chan->redirecting.from.number.valid,
06006 chan->redirecting.from.number.str, "unknown"),
06007 chan->priority,
06008 chan->name,
06009 callerid,
06010 date, (long) time(NULL),
06011 category ? category : "");
06012 } else {
06013 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
06014 inprocess_count(vmu->mailbox, vmu->context, -1);
06015 if (ast_check_realtime("voicemail_data")) {
06016 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06017 }
06018 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
06019 goto leave_vm_out;
06020 }
06021 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag);
06022
06023 if (txt) {
06024 fprintf(txt, "flag=%s\n", flag);
06025 if (sound_duration < vmu->minsecs) {
06026 fclose(txt);
06027 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
06028 ast_filedelete(tmptxtfile, NULL);
06029 unlink(tmptxtfile);
06030 if (ast_check_realtime("voicemail_data")) {
06031 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06032 }
06033 inprocess_count(vmu->mailbox, vmu->context, -1);
06034 } else {
06035 fprintf(txt, "duration=%d\n", duration);
06036 fclose(txt);
06037 if (vm_lock_path(dir)) {
06038 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
06039
06040 ast_filedelete(tmptxtfile, NULL);
06041 unlink(tmptxtfile);
06042 inprocess_count(vmu->mailbox, vmu->context, -1);
06043 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
06044 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
06045 unlink(tmptxtfile);
06046 ast_unlock_path(dir);
06047 inprocess_count(vmu->mailbox, vmu->context, -1);
06048 if (ast_check_realtime("voicemail_data")) {
06049 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06050 }
06051 } else {
06052 #ifndef IMAP_STORAGE
06053 msgnum = last_message_index(vmu, dir) + 1;
06054 #endif
06055 make_file(fn, sizeof(fn), dir, msgnum);
06056
06057
06058 #ifndef IMAP_STORAGE
06059 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
06060 #else
06061 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06062 #endif
06063
06064 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
06065 ast_filerename(tmptxtfile, fn, NULL);
06066 rename(tmptxtfile, txtfile);
06067 inprocess_count(vmu->mailbox, vmu->context, -1);
06068
06069
06070
06071 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
06072 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
06073
06074 ast_unlock_path(dir);
06075 if (ast_check_realtime("voicemail_data")) {
06076 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
06077 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
06078 }
06079
06080
06081
06082 if (ast_fileexists(fn, NULL, NULL) > 0) {
06083 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag);
06084 }
06085
06086
06087 while (tmpptr) {
06088 struct ast_vm_user recipu, *recip;
06089 char *exten, *cntx;
06090
06091 exten = strsep(&tmpptr, "&");
06092 cntx = strchr(exten, '@');
06093 if (cntx) {
06094 *cntx = '\0';
06095 cntx++;
06096 }
06097 if ((recip = find_user(&recipu, cntx, exten))) {
06098 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
06099 free_user(recip);
06100 }
06101 }
06102 #ifndef IMAP_STORAGE
06103 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06104
06105 char sfn[PATH_MAX];
06106 char dfn[PATH_MAX];
06107 int x;
06108
06109 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
06110 x = last_message_index(vmu, urgdir) + 1;
06111 make_file(sfn, sizeof(sfn), dir, msgnum);
06112 make_file(dfn, sizeof(dfn), urgdir, x);
06113 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
06114 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
06115
06116 ast_copy_string(fn, dfn, sizeof(fn));
06117 msgnum = x;
06118 }
06119 #endif
06120
06121 if (ast_fileexists(fn, NULL, NULL)) {
06122 #ifdef IMAP_STORAGE
06123 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
06124 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06125 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06126 flag);
06127 #else
06128 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
06129 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
06130 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
06131 flag);
06132 #endif
06133 }
06134
06135
06136 if (ast_fileexists(fn, NULL, NULL)) {
06137 DISPOSE(dir, msgnum);
06138 }
06139 }
06140 }
06141 } else {
06142 inprocess_count(vmu->mailbox, vmu->context, -1);
06143 }
06144 if (res == '0') {
06145 goto transfer;
06146 } else if (res > 0 && res != 't')
06147 res = 0;
06148
06149 if (sound_duration < vmu->minsecs)
06150
06151 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06152 else
06153 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06154 } else
06155 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06156 leave_vm_out:
06157 free_user(vmu);
06158
06159 #ifdef IMAP_STORAGE
06160
06161 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06162 if (expungeonhangup == 1) {
06163 ast_mutex_lock(&vms->lock);
06164 #ifdef HAVE_IMAP_TK2006
06165 if (LEVELUIDPLUS (vms->mailstream)) {
06166 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06167 } else
06168 #endif
06169 mail_expunge(vms->mailstream);
06170 ast_mutex_unlock(&vms->lock);
06171 }
06172 #endif
06173
06174 ast_free(tmp);
06175 return res;
06176 }
06177
06178 #if !defined(IMAP_STORAGE)
06179 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06180 {
06181
06182
06183 int x, dest;
06184 char sfn[PATH_MAX];
06185 char dfn[PATH_MAX];
06186
06187 if (vm_lock_path(dir)) {
06188 return ERROR_LOCK_PATH;
06189 }
06190
06191 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06192 make_file(sfn, sizeof(sfn), dir, x);
06193 if (EXISTS(dir, x, sfn, NULL)) {
06194
06195 if (x != dest) {
06196 make_file(dfn, sizeof(dfn), dir, dest);
06197 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06198 }
06199
06200 dest++;
06201 }
06202 }
06203 ast_unlock_path(dir);
06204
06205 return dest;
06206 }
06207 #endif
06208
06209 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06210 {
06211 int d;
06212 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06213 return d;
06214 }
06215
06216 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
06217 {
06218 #ifdef IMAP_STORAGE
06219
06220
06221 char sequence[10];
06222 char mailbox[256];
06223 int res;
06224
06225
06226 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06227
06228 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06229 ast_mutex_lock(&vms->lock);
06230
06231 if (box == OLD_FOLDER) {
06232 mail_setflag(vms->mailstream, sequence, "\\Seen");
06233 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06234 } else if (box == NEW_FOLDER) {
06235 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06236 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06237 }
06238 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06239 ast_mutex_unlock(&vms->lock);
06240 return 0;
06241 }
06242
06243 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06244 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06245 if (mail_create(vms->mailstream, mailbox) == NIL)
06246 ast_debug(5, "Folder exists.\n");
06247 else
06248 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06249 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06250 ast_mutex_unlock(&vms->lock);
06251 return res;
06252 #else
06253 char *dir = vms->curdir;
06254 char *username = vms->username;
06255 char *context = vmu->context;
06256 char sfn[PATH_MAX];
06257 char dfn[PATH_MAX];
06258 char ddir[PATH_MAX];
06259 const char *dbox = mbox(vmu, box);
06260 int x, i;
06261 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06262
06263 if (vm_lock_path(ddir))
06264 return ERROR_LOCK_PATH;
06265
06266 x = last_message_index(vmu, ddir) + 1;
06267
06268 if (box == 10 && x >= vmu->maxdeletedmsg) {
06269 x--;
06270 for (i = 1; i <= x; i++) {
06271
06272 make_file(sfn, sizeof(sfn), ddir, i);
06273 make_file(dfn, sizeof(dfn), ddir, i - 1);
06274 if (EXISTS(ddir, i, sfn, NULL)) {
06275 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06276 } else
06277 break;
06278 }
06279 } else {
06280 if (x >= vmu->maxmsg) {
06281 ast_unlock_path(ddir);
06282 return -1;
06283 }
06284 }
06285 make_file(sfn, sizeof(sfn), dir, msg);
06286 make_file(dfn, sizeof(dfn), ddir, x);
06287 if (strcmp(sfn, dfn)) {
06288 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06289 }
06290 ast_unlock_path(ddir);
06291 #endif
06292 return 0;
06293 }
06294
06295 static int adsi_logo(unsigned char *buf)
06296 {
06297 int bytes = 0;
06298 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06299 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06300 return bytes;
06301 }
06302
06303 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06304 {
06305 unsigned char buf[256];
06306 int bytes = 0;
06307 int x;
06308 char num[5];
06309
06310 *useadsi = 0;
06311 bytes += ast_adsi_data_mode(buf + bytes);
06312 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06313
06314 bytes = 0;
06315 bytes += adsi_logo(buf);
06316 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06317 #ifdef DISPLAY
06318 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06319 #endif
06320 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06321 bytes += ast_adsi_data_mode(buf + bytes);
06322 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06323
06324 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06325 bytes = 0;
06326 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06327 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06328 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06329 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06330 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06331 return 0;
06332 }
06333
06334 #ifdef DISPLAY
06335
06336 bytes = 0;
06337 bytes += ast_adsi_logo(buf);
06338 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06339 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06340 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06341 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06342 #endif
06343 bytes = 0;
06344 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06345 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06346 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06347 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06348 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06349 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06350 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06351
06352 #ifdef DISPLAY
06353
06354 bytes = 0;
06355 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06356 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06357
06358 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06359 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06360 #endif
06361
06362 bytes = 0;
06363
06364 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
06365 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
06366 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
06367 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
06368 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
06369 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 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 bytes = 0;
06381 for (x = 0; x < 5; x++) {
06382 snprintf(num, sizeof(num), "%d", x);
06383 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
06384 }
06385 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
06386 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06387
06388 #ifdef DISPLAY
06389
06390 bytes = 0;
06391 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
06392 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06393 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06394 #endif
06395
06396 if (ast_adsi_end_download(chan)) {
06397 bytes = 0;
06398 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
06399 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06400 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06401 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06402 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06403 return 0;
06404 }
06405 bytes = 0;
06406 bytes += ast_adsi_download_disconnect(buf + bytes);
06407 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06408 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06409
06410 ast_debug(1, "Done downloading scripts...\n");
06411
06412 #ifdef DISPLAY
06413
06414 bytes = 0;
06415 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
06416 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06417 #endif
06418 ast_debug(1, "Restarting session...\n");
06419
06420 bytes = 0;
06421
06422 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
06423 *useadsi = 1;
06424 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
06425 } else
06426 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
06427
06428 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06429 return 0;
06430 }
06431
06432 static void adsi_begin(struct ast_channel *chan, int *useadsi)
06433 {
06434 int x;
06435 if (!ast_adsi_available(chan))
06436 return;
06437 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
06438 if (x < 0)
06439 return;
06440 if (!x) {
06441 if (adsi_load_vmail(chan, useadsi)) {
06442 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
06443 return;
06444 }
06445 } else
06446 *useadsi = 1;
06447 }
06448
06449 static void adsi_login(struct ast_channel *chan)
06450 {
06451 unsigned char buf[256];
06452 int bytes = 0;
06453 unsigned char keys[8];
06454 int x;
06455 if (!ast_adsi_available(chan))
06456 return;
06457
06458 for (x = 0; x < 8; x++)
06459 keys[x] = 0;
06460
06461 keys[3] = ADSI_KEY_APPS + 3;
06462
06463 bytes += adsi_logo(buf + bytes);
06464 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
06465 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
06466 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06467 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
06468 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
06469 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
06470 bytes += ast_adsi_set_keys(buf + bytes, keys);
06471 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06472 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06473 }
06474
06475 static void adsi_password(struct ast_channel *chan)
06476 {
06477 unsigned char buf[256];
06478 int bytes = 0;
06479 unsigned char keys[8];
06480 int x;
06481 if (!ast_adsi_available(chan))
06482 return;
06483
06484 for (x = 0; x < 8; x++)
06485 keys[x] = 0;
06486
06487 keys[3] = ADSI_KEY_APPS + 3;
06488
06489 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06490 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
06491 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
06492 bytes += ast_adsi_set_keys(buf + bytes, keys);
06493 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06494 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06495 }
06496
06497 static void adsi_folders(struct ast_channel *chan, int start, char *label)
06498 {
06499 unsigned char buf[256];
06500 int bytes = 0;
06501 unsigned char keys[8];
06502 int x, y;
06503
06504 if (!ast_adsi_available(chan))
06505 return;
06506
06507 for (x = 0; x < 5; x++) {
06508 y = ADSI_KEY_APPS + 12 + start + x;
06509 if (y > ADSI_KEY_APPS + 12 + 4)
06510 y = 0;
06511 keys[x] = ADSI_KEY_SKT | y;
06512 }
06513 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
06514 keys[6] = 0;
06515 keys[7] = 0;
06516
06517 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
06518 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
06519 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06520 bytes += ast_adsi_set_keys(buf + bytes, keys);
06521 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06522
06523 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06524 }
06525
06526 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
06527 {
06528 int bytes = 0;
06529 unsigned char buf[256];
06530 char buf1[256], buf2[256];
06531 char fn2[PATH_MAX];
06532
06533 char cid[256] = "";
06534 char *val;
06535 char *name, *num;
06536 char datetime[21] = "";
06537 FILE *f;
06538
06539 unsigned char keys[8];
06540
06541 int x;
06542
06543 if (!ast_adsi_available(chan))
06544 return;
06545
06546
06547 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
06548 f = fopen(fn2, "r");
06549 if (f) {
06550 while (!feof(f)) {
06551 if (!fgets((char *) buf, sizeof(buf), f)) {
06552 continue;
06553 }
06554 if (!feof(f)) {
06555 char *stringp = NULL;
06556 stringp = (char *) buf;
06557 strsep(&stringp, "=");
06558 val = strsep(&stringp, "=");
06559 if (!ast_strlen_zero(val)) {
06560 if (!strcmp((char *) buf, "callerid"))
06561 ast_copy_string(cid, val, sizeof(cid));
06562 if (!strcmp((char *) buf, "origdate"))
06563 ast_copy_string(datetime, val, sizeof(datetime));
06564 }
06565 }
06566 }
06567 fclose(f);
06568 }
06569
06570 for (x = 0; x < 5; x++)
06571 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06572 keys[6] = 0x0;
06573 keys[7] = 0x0;
06574
06575 if (!vms->curmsg) {
06576
06577 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06578 }
06579 if (vms->curmsg >= vms->lastmsg) {
06580
06581 if (vms->curmsg) {
06582
06583 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06584 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06585
06586 } else {
06587
06588 keys[3] = 1;
06589 }
06590 }
06591
06592 if (!ast_strlen_zero(cid)) {
06593 ast_callerid_parse(cid, &name, &num);
06594 if (!name)
06595 name = num;
06596 } else
06597 name = "Unknown Caller";
06598
06599
06600 #ifdef IMAP_STORAGE
06601 ast_mutex_lock(&vms->lock);
06602 #endif
06603 if (vms->deleted[vms->curmsg]) {
06604 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06605 }
06606 #ifdef IMAP_STORAGE
06607 ast_mutex_unlock(&vms->lock);
06608 #endif
06609
06610
06611 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06612 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
06613 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
06614 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
06615
06616 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06617 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06618 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
06619 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
06620 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06621 bytes += ast_adsi_set_keys(buf + bytes, keys);
06622 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06623
06624 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06625 }
06626
06627 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
06628 {
06629 int bytes = 0;
06630 unsigned char buf[256];
06631 unsigned char keys[8];
06632
06633 int x;
06634
06635 if (!ast_adsi_available(chan))
06636 return;
06637
06638
06639 for (x = 0; x < 5; x++)
06640 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
06641
06642 keys[6] = 0x0;
06643 keys[7] = 0x0;
06644
06645 if (!vms->curmsg) {
06646
06647 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06648 }
06649 if (vms->curmsg >= vms->lastmsg) {
06650
06651 if (vms->curmsg) {
06652
06653 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
06654 } else {
06655
06656 keys[3] = 1;
06657 }
06658 }
06659
06660
06661 #ifdef IMAP_STORAGE
06662 ast_mutex_lock(&vms->lock);
06663 #endif
06664 if (vms->deleted[vms->curmsg]) {
06665 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
06666 }
06667 #ifdef IMAP_STORAGE
06668 ast_mutex_unlock(&vms->lock);
06669 #endif
06670
06671
06672 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
06673 bytes += ast_adsi_set_keys(buf + bytes, keys);
06674 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06675
06676 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06677 }
06678
06679 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
06680 {
06681 unsigned char buf[256] = "";
06682 char buf1[256] = "", buf2[256] = "";
06683 int bytes = 0;
06684 unsigned char keys[8];
06685 int x;
06686
06687 char *newm = (vms->newmessages == 1) ? "message" : "messages";
06688 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
06689 if (!ast_adsi_available(chan))
06690 return;
06691 if (vms->newmessages) {
06692 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
06693 if (vms->oldmessages) {
06694 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
06695 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
06696 } else {
06697 snprintf(buf2, sizeof(buf2), "%s.", newm);
06698 }
06699 } else if (vms->oldmessages) {
06700 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
06701 snprintf(buf2, sizeof(buf2), "%s.", oldm);
06702 } else {
06703 strcpy(buf1, "You have no messages.");
06704 buf2[0] = ' ';
06705 buf2[1] = '\0';
06706 }
06707 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06708 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06709 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06710
06711 for (x = 0; x < 6; x++)
06712 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06713 keys[6] = 0;
06714 keys[7] = 0;
06715
06716
06717 if (vms->lastmsg < 0)
06718 keys[0] = 1;
06719 bytes += ast_adsi_set_keys(buf + bytes, keys);
06720
06721 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06722
06723 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06724 }
06725
06726 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
06727 {
06728 unsigned char buf[256] = "";
06729 char buf1[256] = "", buf2[256] = "";
06730 int bytes = 0;
06731 unsigned char keys[8];
06732 int x;
06733
06734 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
06735
06736 if (!ast_adsi_available(chan))
06737 return;
06738
06739
06740 for (x = 0; x < 6; x++)
06741 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
06742
06743 keys[6] = 0;
06744 keys[7] = 0;
06745
06746 if ((vms->lastmsg + 1) < 1)
06747 keys[0] = 0;
06748
06749 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
06750 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
06751
06752 if (vms->lastmsg + 1)
06753 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
06754 else
06755 strcpy(buf2, "no messages.");
06756 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
06757 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
06758 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
06759 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06760 bytes += ast_adsi_set_keys(buf + bytes, keys);
06761
06762 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06763
06764 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06765
06766 }
06767
06768
06769
06770
06771
06772
06773
06774
06775
06776
06777
06778
06779
06780
06781
06782 static void adsi_goodbye(struct ast_channel *chan)
06783 {
06784 unsigned char buf[256];
06785 int bytes = 0;
06786
06787 if (!ast_adsi_available(chan))
06788 return;
06789 bytes += adsi_logo(buf + bytes);
06790 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
06791 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
06792 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06793 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06794
06795 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06796 }
06797
06798
06799
06800
06801
06802 static int get_folder(struct ast_channel *chan, int start)
06803 {
06804 int x;
06805 int d;
06806 char fn[PATH_MAX];
06807 d = ast_play_and_wait(chan, "vm-press");
06808 if (d)
06809 return d;
06810 for (x = start; x < 5; x++) {
06811 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, NULL)))
06812 return d;
06813 d = ast_play_and_wait(chan, "vm-for");
06814 if (d)
06815 return d;
06816 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
06817
06818
06819
06820
06821 if (x == 0) {
06822 if (ast_fileexists(fn, NULL, NULL)) {
06823 d = vm_play_folder_name(chan, fn);
06824 } else {
06825 ast_verb(1, "failed to find %s\n", fn);
06826 d = vm_play_folder_name(chan, "vm-INBOX");
06827 }
06828 } else {
06829 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
06830 d = vm_play_folder_name(chan, fn);
06831 }
06832
06833 if (d)
06834 return d;
06835 d = ast_waitfordigit(chan, 500);
06836 if (d)
06837 return d;
06838 }
06839
06840 d = ast_play_and_wait(chan, "vm-tocancel");
06841 if (d)
06842 return d;
06843 d = ast_waitfordigit(chan, 4000);
06844 return d;
06845 }
06846
06847
06848
06849
06850
06851
06852
06853
06854
06855
06856
06857
06858
06859 static int get_folder2(struct ast_channel *chan, char *fn, int start)
06860 {
06861 int res = 0;
06862 int loops = 0;
06863
06864 res = ast_play_and_wait(chan, fn);
06865 while (((res < '0') || (res > '9')) &&
06866 (res != '#') && (res >= 0) &&
06867 loops < 4) {
06868 res = get_folder(chan, 0);
06869 loops++;
06870 }
06871 if (loops == 4) {
06872 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
06873 return '#';
06874 }
06875 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
06876 return res;
06877 }
06878
06879
06880
06881
06882
06883
06884
06885
06886
06887
06888
06889
06890
06891
06892
06893
06894
06895
06896
06897 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
06898 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
06899 {
06900 int cmd = 0;
06901 int retries = 0, prepend_duration = 0, already_recorded = 0;
06902 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
06903 char textfile[PATH_MAX];
06904 struct ast_config *msg_cfg;
06905 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
06906 #ifndef IMAP_STORAGE
06907 signed char zero_gain = 0;
06908 #endif
06909 const char *duration_str;
06910
06911
06912 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06913 strcpy(textfile, msgfile);
06914 strcpy(backup, msgfile);
06915 strcpy(backup_textfile, msgfile);
06916 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
06917 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
06918 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
06919
06920 if ((msg_cfg = ast_config_load(textfile, config_flags)) && valid_config(msg_cfg) && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
06921 *duration = atoi(duration_str);
06922 } else {
06923 *duration = 0;
06924 }
06925
06926 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
06927 if (cmd)
06928 retries = 0;
06929 switch (cmd) {
06930 case '1':
06931
06932 #ifdef IMAP_STORAGE
06933
06934 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
06935 strncat(vms->introfn, "intro", sizeof(vms->introfn));
06936 ast_play_and_wait(chan, INTRO);
06937 ast_play_and_wait(chan, "beep");
06938 cmd = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag);
06939 if (cmd == -1) {
06940 break;
06941 }
06942 cmd = 't';
06943 #else
06944
06945
06946
06947 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
06948 strcpy(textfile, msgfile);
06949 strncat(textfile, ".txt", sizeof(textfile) - 1);
06950 *duration = 0;
06951
06952
06953 if (!valid_config(msg_cfg)) {
06954 cmd = 0;
06955 break;
06956 }
06957
06958
06959 #ifndef IMAP_STORAGE
06960 if (already_recorded) {
06961 ast_filecopy(backup, msgfile, NULL);
06962 copy(backup_textfile, textfile);
06963 }
06964 else {
06965 ast_filecopy(msgfile, backup, NULL);
06966 copy(textfile, backup_textfile);
06967 }
06968 #endif
06969 already_recorded = 1;
06970
06971 if (record_gain)
06972 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
06973
06974 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
06975
06976 if (cmd == 'S') {
06977 ast_stream_and_wait(chan, vm_pls_try_again, "");
06978 ast_stream_and_wait(chan, vm_prepend_timeout, "");
06979 ast_filerename(backup, msgfile, NULL);
06980 }
06981
06982 if (record_gain)
06983 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
06984
06985
06986 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
06987 *duration = atoi(duration_str);
06988
06989 if (prepend_duration) {
06990 struct ast_category *msg_cat;
06991
06992 char duration_buf[12];
06993
06994 *duration += prepend_duration;
06995 msg_cat = ast_category_get(msg_cfg, "message");
06996 snprintf(duration_buf, 11, "%ld", *duration);
06997 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
06998 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
06999 }
07000 }
07001
07002 #endif
07003 break;
07004 case '2':
07005
07006 #ifdef IMAP_STORAGE
07007 *vms->introfn = '\0';
07008 #endif
07009 cmd = 't';
07010 break;
07011 case '*':
07012 cmd = '*';
07013 break;
07014 default:
07015
07016 already_recorded = 0;
07017
07018 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
07019
07020 if (!cmd) {
07021 cmd = ast_play_and_wait(chan, "vm-starmain");
07022
07023 }
07024 if (!cmd) {
07025 cmd = ast_waitfordigit(chan, 6000);
07026 }
07027 if (!cmd) {
07028 retries++;
07029 }
07030 if (retries > 3) {
07031 cmd = '*';
07032 }
07033 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07034 }
07035 }
07036
07037 if (valid_config(msg_cfg))
07038 ast_config_destroy(msg_cfg);
07039 if (prepend_duration)
07040 *duration = prepend_duration;
07041
07042 if (already_recorded && cmd == -1) {
07043
07044 ast_filerename(backup, msgfile, NULL);
07045 rename(backup_textfile, textfile);
07046 }
07047
07048 if (cmd == 't' || cmd == 'S')
07049 cmd = 0;
07050 return cmd;
07051 }
07052
07053 static void queue_mwi_event(const char *box, int urgent, int new, int old)
07054 {
07055 struct ast_event *event;
07056 char *mailbox, *context;
07057
07058
07059 context = mailbox = ast_strdupa(box);
07060 strsep(&context, "@");
07061 if (ast_strlen_zero(context))
07062 context = "default";
07063
07064 if (!(event = ast_event_new(AST_EVENT_MWI,
07065 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
07066 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
07067 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
07068 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
07069 AST_EVENT_IE_END))) {
07070 return;
07071 }
07072
07073 ast_event_queue_and_cache(event);
07074 }
07075
07076
07077
07078
07079
07080
07081
07082
07083
07084
07085
07086
07087
07088
07089
07090 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)
07091 {
07092 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
07093 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
07094 const char *category;
07095 char *myserveremail = serveremail;
07096
07097 ast_channel_lock(chan);
07098 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
07099 category = ast_strdupa(category);
07100 }
07101 ast_channel_unlock(chan);
07102
07103 #ifndef IMAP_STORAGE
07104 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
07105 #else
07106 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
07107 #endif
07108 make_file(fn, sizeof(fn), todir, msgnum);
07109 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
07110
07111 if (!ast_strlen_zero(vmu->attachfmt)) {
07112 if (strstr(fmt, vmu->attachfmt))
07113 fmt = vmu->attachfmt;
07114 else
07115 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);
07116 }
07117
07118
07119 fmt = ast_strdupa(fmt);
07120 stringp = fmt;
07121 strsep(&stringp, "|");
07122
07123 if (!ast_strlen_zero(vmu->serveremail))
07124 myserveremail = vmu->serveremail;
07125
07126 if (!ast_strlen_zero(vmu->email)) {
07127 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
07128
07129 if (attach_user_voicemail)
07130 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
07131
07132
07133 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
07134
07135 if (attach_user_voicemail)
07136 DISPOSE(todir, msgnum);
07137 }
07138
07139 if (!ast_strlen_zero(vmu->pager)) {
07140 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
07141 }
07142
07143 if (ast_test_flag(vmu, VM_DELETE))
07144 DELETE(todir, msgnum, fn, vmu);
07145
07146
07147 if (ast_app_has_voicemail(ext_context, NULL))
07148 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
07149
07150 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
07151
07152 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);
07153 run_externnotify(vmu->context, vmu->mailbox, flag);
07154
07155 #ifdef IMAP_STORAGE
07156 vm_delete(fn);
07157 if (ast_test_flag(vmu, VM_DELETE)) {
07158 vm_imap_delete(NULL, vms->curmsg, vmu);
07159 vms->newmessages--;
07160 }
07161 #endif
07162
07163 return 0;
07164 }
07165
07166
07167
07168
07169
07170
07171
07172
07173
07174
07175
07176
07177
07178
07179
07180
07181
07182
07183
07184
07185
07186
07187
07188
07189
07190
07191
07192
07193 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)
07194 {
07195 #ifdef IMAP_STORAGE
07196 int todircount = 0;
07197 struct vm_state *dstvms;
07198 #endif
07199 char username[70]="";
07200 char fn[PATH_MAX];
07201 char ecodes[16] = "#";
07202 int res = 0, cmd = 0;
07203 struct ast_vm_user *receiver = NULL, *vmtmp;
07204 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
07205 char *stringp;
07206 const char *s;
07207 int saved_messages = 0;
07208 int valid_extensions = 0;
07209 char *dir;
07210 int curmsg;
07211 char urgent_str[7] = "";
07212 int prompt_played = 0;
07213 #ifndef IMAP_STORAGE
07214 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07215 #endif
07216 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07217 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07218 }
07219
07220 if (vms == NULL) return -1;
07221 dir = vms->curdir;
07222 curmsg = vms->curmsg;
07223
07224 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
07225 while (!res && !valid_extensions) {
07226 int use_directory = 0;
07227 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07228 int done = 0;
07229 int retries = 0;
07230 cmd = 0;
07231 while ((cmd >= 0) && !done ){
07232 if (cmd)
07233 retries = 0;
07234 switch (cmd) {
07235 case '1':
07236 use_directory = 0;
07237 done = 1;
07238 break;
07239 case '2':
07240 use_directory = 1;
07241 done = 1;
07242 break;
07243 case '*':
07244 cmd = 't';
07245 done = 1;
07246 break;
07247 default:
07248
07249 cmd = ast_play_and_wait(chan, "vm-forward");
07250 if (!cmd) {
07251 cmd = ast_waitfordigit(chan, 3000);
07252 }
07253 if (!cmd) {
07254 retries++;
07255 }
07256 if (retries > 3) {
07257 cmd = 't';
07258 done = 1;
07259 }
07260 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07261 }
07262 }
07263 if (cmd < 0 || cmd == 't')
07264 break;
07265 }
07266
07267 if (use_directory) {
07268
07269
07270 char old_context[sizeof(chan->context)];
07271 char old_exten[sizeof(chan->exten)];
07272 int old_priority;
07273 struct ast_app* directory_app;
07274
07275 directory_app = pbx_findapp("Directory");
07276 if (directory_app) {
07277 char vmcontext[256];
07278
07279 memcpy(old_context, chan->context, sizeof(chan->context));
07280 memcpy(old_exten, chan->exten, sizeof(chan->exten));
07281 old_priority = chan->priority;
07282
07283
07284 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07285 res = pbx_exec(chan, directory_app, vmcontext);
07286
07287 ast_copy_string(username, chan->exten, sizeof(username));
07288
07289
07290 memcpy(chan->context, old_context, sizeof(chan->context));
07291 memcpy(chan->exten, old_exten, sizeof(chan->exten));
07292 chan->priority = old_priority;
07293 } else {
07294 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07295 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07296 }
07297 } else {
07298
07299 res = ast_streamfile(chan, "vm-extension", chan->language);
07300 prompt_played++;
07301 if (res || prompt_played > 4)
07302 break;
07303 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
07304 break;
07305 }
07306
07307
07308 if (ast_strlen_zero(username))
07309 continue;
07310 stringp = username;
07311 s = strsep(&stringp, "*");
07312
07313 valid_extensions = 1;
07314 while (s) {
07315 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
07316 int oldmsgs;
07317 int newmsgs;
07318 int capacity;
07319 if (inboxcount(s, &newmsgs, &oldmsgs)) {
07320 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
07321
07322 res = ast_play_and_wait(chan, "pbx-invalid");
07323 valid_extensions = 0;
07324 break;
07325 }
07326 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
07327 if ((newmsgs + oldmsgs) >= capacity) {
07328 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
07329 res = ast_play_and_wait(chan, "vm-mailboxfull");
07330 valid_extensions = 0;
07331 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07332 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07333 free_user(vmtmp);
07334 }
07335 inprocess_count(receiver->mailbox, receiver->context, -1);
07336 break;
07337 }
07338 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
07339 } else {
07340
07341
07342
07343
07344
07345 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07346 free_user(receiver);
07347 }
07348 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
07349
07350 res = ast_play_and_wait(chan, "pbx-invalid");
07351 valid_extensions = 0;
07352 break;
07353 }
07354
07355
07356 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
07357 RETRIEVE(fn, -1, s, receiver->context);
07358 if (ast_fileexists(fn, NULL, NULL) > 0) {
07359 res = ast_stream_and_wait(chan, fn, ecodes);
07360 if (res) {
07361 DISPOSE(fn, -1);
07362 return res;
07363 }
07364 } else {
07365 res = ast_say_digit_str(chan, s, ecodes, chan->language);
07366 }
07367 DISPOSE(fn, -1);
07368
07369 s = strsep(&stringp, "*");
07370 }
07371
07372 if (valid_extensions)
07373 break;
07374 }
07375
07376 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
07377 return res;
07378 if (is_new_message == 1) {
07379 struct leave_vm_options leave_options;
07380 char mailbox[AST_MAX_EXTENSION * 2 + 2];
07381 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
07382
07383
07384 memset(&leave_options, 0, sizeof(leave_options));
07385 leave_options.record_gain = record_gain;
07386 cmd = leave_voicemail(chan, mailbox, &leave_options);
07387 } else {
07388
07389 long duration = 0;
07390 struct vm_state vmstmp;
07391 int copy_msg_result = 0;
07392 memcpy(&vmstmp, vms, sizeof(vmstmp));
07393
07394 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
07395
07396 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
07397 if (!cmd) {
07398 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
07399 #ifdef IMAP_STORAGE
07400 int attach_user_voicemail;
07401 char *myserveremail = serveremail;
07402
07403
07404 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
07405 if (!dstvms) {
07406 dstvms = create_vm_state_from_user(vmtmp);
07407 }
07408 if (dstvms) {
07409 init_mailstream(dstvms, 0);
07410 if (!dstvms->mailstream) {
07411 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
07412 } else {
07413 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
07414 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
07415 }
07416 } else {
07417 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
07418 }
07419 if (!ast_strlen_zero(vmtmp->serveremail))
07420 myserveremail = vmtmp->serveremail;
07421 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
07422
07423 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
07424 dstvms->curbox,
07425 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
07426 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, NULL),
07427 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
07428 NULL, urgent_str);
07429 #else
07430 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
07431 #endif
07432 saved_messages++;
07433 AST_LIST_REMOVE_CURRENT(list);
07434 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07435 free_user(vmtmp);
07436 if (res)
07437 break;
07438 }
07439 AST_LIST_TRAVERSE_SAFE_END;
07440 if (saved_messages > 0 && !copy_msg_result) {
07441
07442
07443
07444
07445
07446
07447
07448
07449 #ifdef IMAP_STORAGE
07450
07451 if (ast_strlen_zero(vmstmp.introfn))
07452 #endif
07453 res = ast_play_and_wait(chan, "vm-msgsaved");
07454 }
07455 #ifndef IMAP_STORAGE
07456 else {
07457
07458 res = ast_play_and_wait(chan, "vm-mailboxfull");
07459 }
07460
07461 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07462 strcpy(textfile, msgfile);
07463 strcpy(backup, msgfile);
07464 strcpy(backup_textfile, msgfile);
07465 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07466 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07467 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07468 if (ast_fileexists(backup, NULL, NULL) > 0) {
07469 ast_filerename(backup, msgfile, NULL);
07470 rename(backup_textfile, textfile);
07471 }
07472 #endif
07473 }
07474 DISPOSE(dir, curmsg);
07475 #ifndef IMAP_STORAGE
07476 if (cmd) {
07477 make_file(msgfile, sizeof(msgfile), dir, curmsg);
07478 strcpy(textfile, msgfile);
07479 strcpy(backup_textfile, msgfile);
07480 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07481 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07482 rename(backup_textfile, textfile);
07483 }
07484 #endif
07485 }
07486
07487
07488 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
07489 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
07490 free_user(vmtmp);
07491 }
07492 return res ? res : cmd;
07493 }
07494
07495 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
07496 {
07497 int res;
07498 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
07499 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
07500 return res;
07501 }
07502
07503 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
07504 {
07505 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
07506 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);
07507 }
07508
07509 static int play_message_category(struct ast_channel *chan, const char *category)
07510 {
07511 int res = 0;
07512
07513 if (!ast_strlen_zero(category))
07514 res = ast_play_and_wait(chan, category);
07515
07516 if (res) {
07517 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
07518 res = 0;
07519 }
07520
07521 return res;
07522 }
07523
07524 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
07525 {
07526 int res = 0;
07527 struct vm_zone *the_zone = NULL;
07528 time_t t;
07529
07530 if (ast_get_time_t(origtime, &t, 0, NULL)) {
07531 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
07532 return 0;
07533 }
07534
07535
07536 if (!ast_strlen_zero(vmu->zonetag)) {
07537
07538 struct vm_zone *z;
07539 AST_LIST_LOCK(&zones);
07540 AST_LIST_TRAVERSE(&zones, z, list) {
07541 if (!strcmp(z->name, vmu->zonetag)) {
07542 the_zone = z;
07543 break;
07544 }
07545 }
07546 AST_LIST_UNLOCK(&zones);
07547 }
07548
07549
07550 #if 0
07551
07552 ast_localtime(&t, &time_now, NULL);
07553 tv_now = ast_tvnow();
07554 ast_localtime(&tv_now, &time_then, NULL);
07555
07556
07557 if (time_now.tm_year == time_then.tm_year)
07558 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
07559 else
07560 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
07561 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
07562
07563
07564 #endif
07565 if (the_zone) {
07566 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, the_zone->msg_format, the_zone->timezone);
07567 } else if (!strncasecmp(chan->language, "de", 2)) {
07568 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07569 } else if (!strncasecmp(chan->language, "gr", 2)) {
07570 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q H 'digits/kai' M ", NULL);
07571 } else if (!strncasecmp(chan->language, "it", 2)) {
07572 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);
07573 } else if (!strncasecmp(chan->language, "nl", 2)) {
07574 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/nl-om' HM", NULL);
07575 } else if (!strncasecmp(chan->language, "no", 2)) {
07576 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q 'digits/at' HM", NULL);
07577 } else if (!strncasecmp(chan->language, "pl", 2)) {
07578 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' Q HM", NULL);
07579 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
07580 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);
07581 } else if (!strncasecmp(chan->language, "se", 2)) {
07582 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' dB 'digits/at' k 'and' M", NULL);
07583 } else if (!strncasecmp(chan->language, "zh", 2)) {
07584 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "qR 'vm-received'", NULL);
07585 } else if (!strncasecmp(chan->language, "vi", 2)) {
07586 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);
07587 } else {
07588 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, chan->language, "'vm-received' q 'digits/at' IMp", NULL);
07589 }
07590 #if 0
07591 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
07592 #endif
07593 return res;
07594 }
07595
07596
07597
07598 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
07599 {
07600 int res = 0;
07601 int i;
07602 char *callerid, *name;
07603 char prefile[PATH_MAX] = "";
07604
07605
07606
07607
07608
07609
07610
07611
07612
07613 if ((cid == NULL)||(context == NULL))
07614 return res;
07615
07616
07617 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
07618 ast_callerid_parse(cid, &name, &callerid);
07619 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
07620
07621
07622 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
07623 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
07624 if ((strcmp(cidinternalcontexts[i], context) == 0))
07625 break;
07626 }
07627 if (i != MAX_NUM_CID_CONTEXTS){
07628 if (!res) {
07629 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
07630 if (!ast_strlen_zero(prefile)) {
07631
07632 if (ast_fileexists(prefile, NULL, NULL) > 0) {
07633 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
07634 if (!callback)
07635 res = wait_file2(chan, vms, "vm-from");
07636 res = ast_stream_and_wait(chan, prefile, "");
07637 } else {
07638 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
07639
07640 if (!callback)
07641 res = wait_file2(chan, vms, "vm-from-extension");
07642 res = ast_say_digit_str(chan, callerid, "", chan->language);
07643 }
07644 }
07645 }
07646 } else if (!res) {
07647 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
07648
07649 if (!callback)
07650 res = wait_file2(chan, vms, "vm-from-phonenumber");
07651 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, chan->language);
07652 }
07653 } else {
07654
07655 ast_debug(1, "VM-CID: From an unknown number\n");
07656
07657 res = wait_file2(chan, vms, "vm-unknown-caller");
07658 }
07659 return res;
07660 }
07661
07662 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
07663 {
07664 int res = 0;
07665 int durationm;
07666 int durations;
07667
07668 if (duration == NULL)
07669 return res;
07670
07671
07672 durations = atoi(duration);
07673 durationm = (durations / 60);
07674
07675 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
07676
07677 if ((!res) && (durationm >= minduration)) {
07678 res = wait_file2(chan, vms, "vm-duration");
07679
07680
07681 if (!strncasecmp(chan->language, "pl", 2)) {
07682 div_t num = div(durationm, 10);
07683
07684 if (durationm == 1) {
07685 res = ast_play_and_wait(chan, "digits/1z");
07686 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
07687 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
07688 if (num.rem == 2) {
07689 if (!num.quot) {
07690 res = ast_play_and_wait(chan, "digits/2-ie");
07691 } else {
07692 res = say_and_wait(chan, durationm - 2 , chan->language);
07693 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
07694 }
07695 } else {
07696 res = say_and_wait(chan, durationm, chan->language);
07697 }
07698 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
07699 } else {
07700 res = say_and_wait(chan, durationm, chan->language);
07701 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
07702 }
07703
07704 } else {
07705 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, chan->language, NULL);
07706 res = wait_file2(chan, vms, "vm-minutes");
07707 }
07708 }
07709 return res;
07710 }
07711
07712 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
07713 {
07714 int res = 0;
07715 char filename[256], *cid;
07716 const char *origtime, *context, *category, *duration, *flag;
07717 struct ast_config *msg_cfg;
07718 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07719
07720 vms->starting = 0;
07721 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07722 adsi_message(chan, vms);
07723 if (!vms->curmsg) {
07724 res = wait_file2(chan, vms, "vm-first");
07725 } else if (vms->curmsg == vms->lastmsg) {
07726 res = wait_file2(chan, vms, "vm-last");
07727 }
07728
07729 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
07730 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
07731 msg_cfg = ast_config_load(filename, config_flags);
07732 if (!valid_config(msg_cfg)) {
07733 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07734 return 0;
07735 }
07736 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
07737
07738
07739 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
07740 res = wait_file2(chan, vms, "vm-Urgent");
07741 }
07742
07743 if (!res) {
07744
07745
07746 if (!strncasecmp(chan->language, "pl", 2)) {
07747 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07748 int ten, one;
07749 char nextmsg[256];
07750 ten = (vms->curmsg + 1) / 10;
07751 one = (vms->curmsg + 1) % 10;
07752
07753 if (vms->curmsg < 20) {
07754 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
07755 res = wait_file2(chan, vms, nextmsg);
07756 } else {
07757 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
07758 res = wait_file2(chan, vms, nextmsg);
07759 if (one > 0) {
07760 if (!res) {
07761 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
07762 res = wait_file2(chan, vms, nextmsg);
07763 }
07764 }
07765 }
07766 }
07767 if (!res)
07768 res = wait_file2(chan, vms, "vm-message");
07769
07770 } else if (!strncasecmp(chan->language, "he", 2)) {
07771 if (!vms->curmsg) {
07772 res = wait_file2(chan, vms, "vm-message");
07773 res = wait_file2(chan, vms, "vm-first");
07774 } else if (vms->curmsg == vms->lastmsg) {
07775 res = wait_file2(chan, vms, "vm-message");
07776 res = wait_file2(chan, vms, "vm-last");
07777 } else {
07778 res = wait_file2(chan, vms, "vm-message");
07779 res = wait_file2(chan, vms, "vm-number");
07780 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07781 }
07782
07783 } else if (!strncasecmp(chan->language, "vi", 2)) {
07784 if (!vms->curmsg) {
07785 res = wait_file2(chan, vms, "vm-message");
07786 res = wait_file2(chan, vms, "vm-first");
07787 } else if (vms->curmsg == vms->lastmsg) {
07788 res = wait_file2(chan, vms, "vm-message");
07789 res = wait_file2(chan, vms, "vm-last");
07790 } else {
07791 res = wait_file2(chan, vms, "vm-message");
07792 res = wait_file2(chan, vms, "vm-number");
07793 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, "f");
07794 }
07795 } else {
07796 if (!strncasecmp(chan->language, "se", 2)) {
07797 res = wait_file2(chan, vms, "vm-meddelandet");
07798 } else {
07799 res = wait_file2(chan, vms, "vm-message");
07800 }
07801 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
07802 if (!res) {
07803 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
07804 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, chan->language, NULL);
07805 }
07806 }
07807 }
07808 }
07809
07810 if (!valid_config(msg_cfg)) {
07811 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
07812 return 0;
07813 }
07814
07815 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
07816 ast_log(AST_LOG_WARNING, "No origtime?!\n");
07817 DISPOSE(vms->curdir, vms->curmsg);
07818 ast_config_destroy(msg_cfg);
07819 return 0;
07820 }
07821
07822 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
07823 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
07824 category = ast_variable_retrieve(msg_cfg, "message", "category");
07825
07826 context = ast_variable_retrieve(msg_cfg, "message", "context");
07827 if (!strncasecmp("macro", context, 5))
07828 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
07829 if (!res) {
07830 res = play_message_category(chan, category);
07831 }
07832 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
07833 res = play_message_datetime(chan, vmu, origtime, filename);
07834 }
07835 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
07836 res = play_message_callerid(chan, vms, cid, context, 0);
07837 }
07838 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
07839 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
07840 }
07841
07842 if (res == '1') {
07843 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07844 res = 0;
07845 }
07846 ast_config_destroy(msg_cfg);
07847
07848 if (!res) {
07849 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
07850 #ifdef IMAP_STORAGE
07851 ast_mutex_lock(&vms->lock);
07852 #endif
07853 vms->heard[vms->curmsg] = 1;
07854 #ifdef IMAP_STORAGE
07855 ast_mutex_unlock(&vms->lock);
07856
07857
07858
07859 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
07860 wait_file(chan, vms, vms->introfn);
07861 }
07862 #endif
07863 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
07864 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
07865 res = 0;
07866 }
07867 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07868 }
07869 DISPOSE(vms->curdir, vms->curmsg);
07870 return res;
07871 }
07872
07873 #ifdef IMAP_STORAGE
07874 static int imap_remove_file(char *dir, int msgnum)
07875 {
07876 char fn[PATH_MAX];
07877 char full_fn[PATH_MAX];
07878 char intro[PATH_MAX] = {0,};
07879
07880 if (msgnum > -1) {
07881 make_file(fn, sizeof(fn), dir, msgnum);
07882 snprintf(intro, sizeof(intro), "%sintro", fn);
07883 } else
07884 ast_copy_string(fn, dir, sizeof(fn));
07885
07886 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
07887 ast_filedelete(fn, NULL);
07888 if (!ast_strlen_zero(intro)) {
07889 ast_filedelete(intro, NULL);
07890 }
07891 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
07892 unlink(full_fn);
07893 }
07894 return 0;
07895 }
07896
07897
07898
07899 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
07900 {
07901 char *file, *filename;
07902 char *attachment;
07903 char arg[10];
07904 int i;
07905 BODY* body;
07906
07907 file = strrchr(ast_strdupa(dir), '/');
07908 if (file) {
07909 *file++ = '\0';
07910 } else {
07911 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
07912 return -1;
07913 }
07914
07915 ast_mutex_lock(&vms->lock);
07916 for (i = 0; i < vms->mailstream->nmsgs; i++) {
07917 mail_fetchstructure(vms->mailstream, i + 1, &body);
07918
07919 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
07920 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
07921 } else {
07922 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
07923 ast_mutex_unlock(&vms->lock);
07924 return -1;
07925 }
07926 filename = strsep(&attachment, ".");
07927 if (!strcmp(filename, file)) {
07928 sprintf(arg, "%d", i + 1);
07929 mail_setflag(vms->mailstream, arg, "\\DELETED");
07930 }
07931 }
07932 mail_expunge(vms->mailstream);
07933 ast_mutex_unlock(&vms->lock);
07934 return 0;
07935 }
07936
07937 #elif !defined(IMAP_STORAGE)
07938 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
07939 {
07940 int count_msg, last_msg;
07941
07942 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
07943
07944
07945
07946
07947 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
07948
07949
07950 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
07951
07952
07953 count_msg = count_messages(vmu, vms->curdir);
07954 if (count_msg < 0) {
07955 return count_msg;
07956 } else {
07957 vms->lastmsg = count_msg - 1;
07958 }
07959
07960 if (vm_allocate_dh(vms, vmu, count_msg)) {
07961 return -1;
07962 }
07963
07964
07965
07966
07967
07968
07969
07970
07971 if (vm_lock_path(vms->curdir)) {
07972 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
07973 return ERROR_LOCK_PATH;
07974 }
07975
07976
07977 last_msg = last_message_index(vmu, vms->curdir);
07978 ast_unlock_path(vms->curdir);
07979
07980 if (last_msg < -1) {
07981 return last_msg;
07982 } else if (vms->lastmsg != last_msg) {
07983 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);
07984 resequence_mailbox(vmu, vms->curdir, count_msg);
07985 }
07986
07987 return 0;
07988 }
07989 #endif
07990
07991 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
07992 {
07993 int x = 0;
07994 int last_msg_idx = 0;
07995
07996 #ifndef IMAP_STORAGE
07997 int res = 0, nummsg;
07998 char fn2[PATH_MAX];
07999 #endif
08000
08001 if (vms->lastmsg <= -1) {
08002 goto done;
08003 }
08004
08005 vms->curmsg = -1;
08006 #ifndef IMAP_STORAGE
08007
08008 if (vm_lock_path(vms->curdir)) {
08009 return ERROR_LOCK_PATH;
08010 }
08011
08012
08013 last_msg_idx = last_message_index(vmu, vms->curdir);
08014 if (last_msg_idx != vms->lastmsg) {
08015 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
08016 }
08017
08018
08019 for (x = 0; x < last_msg_idx + 1; x++) {
08020 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
08021
08022 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08023 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
08024 break;
08025 }
08026 vms->curmsg++;
08027 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
08028 if (strcmp(vms->fn, fn2)) {
08029 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
08030 }
08031 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
08032
08033 res = save_to_folder(vmu, vms, x, 1);
08034 if (res == ERROR_LOCK_PATH) {
08035
08036 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
08037 vms->deleted[x] = 0;
08038 vms->heard[x] = 0;
08039 --x;
08040 }
08041 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
08042
08043 res = save_to_folder(vmu, vms, x, 10);
08044 if (res == ERROR_LOCK_PATH) {
08045
08046 vms->deleted[x] = 0;
08047 vms->heard[x] = 0;
08048 --x;
08049 }
08050 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
08051
08052
08053 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08054 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08055 DELETE(vms->curdir, x, vms->fn, vmu);
08056 }
08057 }
08058 }
08059
08060
08061 nummsg = x - 1;
08062 for (x = vms->curmsg + 1; x <= nummsg; x++) {
08063 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08064 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08065 DELETE(vms->curdir, x, vms->fn, vmu);
08066 }
08067 }
08068 ast_unlock_path(vms->curdir);
08069 #else
08070 ast_mutex_lock(&vms->lock);
08071 if (vms->deleted) {
08072
08073
08074 last_msg_idx = vms->dh_arraysize;
08075 for (x = last_msg_idx - 1; x >= 0; x--) {
08076 if (vms->deleted[x]) {
08077 ast_debug(3, "IMAP delete of %d\n", x);
08078 DELETE(vms->curdir, x, vms->fn, vmu);
08079 }
08080 }
08081 }
08082 #endif
08083
08084 done:
08085 if (vms->deleted) {
08086 ast_free(vms->deleted);
08087 vms->deleted = NULL;
08088 }
08089 if (vms->heard) {
08090 ast_free(vms->heard);
08091 vms->heard = NULL;
08092 }
08093 vms->dh_arraysize = 0;
08094 #ifdef IMAP_STORAGE
08095 ast_mutex_unlock(&vms->lock);
08096 #endif
08097
08098 return 0;
08099 }
08100
08101
08102
08103
08104
08105
08106
08107 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08108 {
08109 int cmd;
08110 char *buf;
08111
08112 buf = ast_alloca(strlen(box) + 2);
08113 strcpy(buf, box);
08114 strcat(buf, "s");
08115
08116 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08117 cmd = ast_play_and_wait(chan, buf);
08118 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08119 } else {
08120 cmd = ast_play_and_wait(chan, "vm-messages");
08121 return cmd ? cmd : ast_play_and_wait(chan, box);
08122 }
08123 }
08124
08125 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08126 {
08127 int cmd;
08128
08129 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08130 if (!strcasecmp(box, "vm-INBOX"))
08131 cmd = ast_play_and_wait(chan, "vm-new-e");
08132 else
08133 cmd = ast_play_and_wait(chan, "vm-old-e");
08134 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08135 } else {
08136 cmd = ast_play_and_wait(chan, "vm-messages");
08137 return cmd ? cmd : ast_play_and_wait(chan, box);
08138 }
08139 }
08140
08141 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08142 {
08143 int cmd;
08144
08145 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08146 cmd = ast_play_and_wait(chan, "vm-messages");
08147 return cmd ? cmd : ast_play_and_wait(chan, box);
08148 } else {
08149 cmd = ast_play_and_wait(chan, box);
08150 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08151 }
08152 }
08153
08154 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08155 {
08156 int cmd;
08157
08158 if ( !strncasecmp(chan->language, "it", 2) ||
08159 !strncasecmp(chan->language, "es", 2) ||
08160 !strncasecmp(chan->language, "pt", 2)) {
08161 cmd = ast_play_and_wait(chan, "vm-messages");
08162 return cmd ? cmd : ast_play_and_wait(chan, box);
08163 } else if (!strncasecmp(chan->language, "gr", 2)) {
08164 return vm_play_folder_name_gr(chan, box);
08165 } else if (!strncasecmp(chan->language, "he", 2)) {
08166 return ast_play_and_wait(chan, box);
08167 } else if (!strncasecmp(chan->language, "pl", 2)) {
08168 return vm_play_folder_name_pl(chan, box);
08169 } else if (!strncasecmp(chan->language, "ua", 2)) {
08170 return vm_play_folder_name_ua(chan, box);
08171 } else if (!strncasecmp(chan->language, "vi", 2)) {
08172 return ast_play_and_wait(chan, box);
08173 } else {
08174 cmd = ast_play_and_wait(chan, box);
08175 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08176 }
08177 }
08178
08179
08180
08181
08182
08183
08184
08185
08186
08187
08188
08189
08190
08191 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08192 {
08193 int res = 0;
08194
08195 if (vms->newmessages) {
08196 res = ast_play_and_wait(chan, "vm-youhave");
08197 if (!res)
08198 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, NULL);
08199 if (!res) {
08200 if ((vms->newmessages == 1)) {
08201 res = ast_play_and_wait(chan, "vm-INBOX");
08202 if (!res)
08203 res = ast_play_and_wait(chan, "vm-message");
08204 } else {
08205 res = ast_play_and_wait(chan, "vm-INBOXs");
08206 if (!res)
08207 res = ast_play_and_wait(chan, "vm-messages");
08208 }
08209 }
08210 } else if (vms->oldmessages){
08211 res = ast_play_and_wait(chan, "vm-youhave");
08212 if (!res)
08213 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, NULL);
08214 if ((vms->oldmessages == 1)){
08215 res = ast_play_and_wait(chan, "vm-Old");
08216 if (!res)
08217 res = ast_play_and_wait(chan, "vm-message");
08218 } else {
08219 res = ast_play_and_wait(chan, "vm-Olds");
08220 if (!res)
08221 res = ast_play_and_wait(chan, "vm-messages");
08222 }
08223 } else if (!vms->oldmessages && !vms->newmessages)
08224 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08225 return res;
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
08271
08272
08273
08274
08275
08276
08277
08278
08279
08280
08281
08282
08283
08284
08285 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
08286 {
08287 int res;
08288 int lastnum = 0;
08289
08290 res = ast_play_and_wait(chan, "vm-youhave");
08291
08292 if (!res && vms->newmessages) {
08293 lastnum = vms->newmessages;
08294
08295 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08296 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
08297 }
08298
08299 if (!res && vms->oldmessages) {
08300 res = ast_play_and_wait(chan, "vm-and");
08301 }
08302 }
08303
08304 if (!res && vms->oldmessages) {
08305 lastnum = vms->oldmessages;
08306
08307 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, chan->language, message_gender))) {
08308 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
08309 }
08310 }
08311
08312 if (!res) {
08313 if (lastnum == 0) {
08314 res = ast_play_and_wait(chan, "vm-no");
08315 }
08316 if (!res) {
08317 res = ast_say_counted_noun(chan, lastnum, "vm-message");
08318 }
08319 }
08320
08321 return res;
08322 }
08323
08324
08325 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
08326 {
08327 int res = 0;
08328
08329
08330 if (!res) {
08331 if ((vms->newmessages) || (vms->oldmessages)) {
08332 res = ast_play_and_wait(chan, "vm-youhave");
08333 }
08334
08335
08336
08337
08338
08339 if (vms->newmessages) {
08340 if (!res) {
08341 if (vms->newmessages == 1) {
08342 res = ast_play_and_wait(chan, "vm-INBOX1");
08343 } else {
08344 if (vms->newmessages == 2) {
08345 res = ast_play_and_wait(chan, "vm-shtei");
08346 } else {
08347 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08348 }
08349 res = ast_play_and_wait(chan, "vm-INBOX");
08350 }
08351 }
08352 if (vms->oldmessages && !res) {
08353 res = ast_play_and_wait(chan, "vm-and");
08354 if (vms->oldmessages == 1) {
08355 res = ast_play_and_wait(chan, "vm-Old1");
08356 } else {
08357 if (vms->oldmessages == 2) {
08358 res = ast_play_and_wait(chan, "vm-shtei");
08359 } else {
08360 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08361 }
08362 res = ast_play_and_wait(chan, "vm-Old");
08363 }
08364 }
08365 }
08366 if (!res && vms->oldmessages && !vms->newmessages) {
08367 if (!res) {
08368 if (vms->oldmessages == 1) {
08369 res = ast_play_and_wait(chan, "vm-Old1");
08370 } else {
08371 if (vms->oldmessages == 2) {
08372 res = ast_play_and_wait(chan, "vm-shtei");
08373 } else {
08374 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08375 }
08376 res = ast_play_and_wait(chan, "vm-Old");
08377 }
08378 }
08379 }
08380 if (!res) {
08381 if (!vms->oldmessages && !vms->newmessages) {
08382 if (!res) {
08383 res = ast_play_and_wait(chan, "vm-nomessages");
08384 }
08385 }
08386 }
08387 }
08388 return res;
08389 }
08390
08391
08392 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
08393 {
08394 int res;
08395
08396
08397 res = ast_play_and_wait(chan, "vm-youhave");
08398 if (!res) {
08399 if (vms->urgentmessages) {
08400 res = say_and_wait(chan, vms->urgentmessages, chan->language);
08401 if (!res)
08402 res = ast_play_and_wait(chan, "vm-Urgent");
08403 if ((vms->oldmessages || vms->newmessages) && !res) {
08404 res = ast_play_and_wait(chan, "vm-and");
08405 } else if (!res) {
08406 if ((vms->urgentmessages == 1))
08407 res = ast_play_and_wait(chan, "vm-message");
08408 else
08409 res = ast_play_and_wait(chan, "vm-messages");
08410 }
08411 }
08412 if (vms->newmessages) {
08413 res = say_and_wait(chan, vms->newmessages, chan->language);
08414 if (!res)
08415 res = ast_play_and_wait(chan, "vm-INBOX");
08416 if (vms->oldmessages && !res)
08417 res = ast_play_and_wait(chan, "vm-and");
08418 else if (!res) {
08419 if ((vms->newmessages == 1))
08420 res = ast_play_and_wait(chan, "vm-message");
08421 else
08422 res = ast_play_and_wait(chan, "vm-messages");
08423 }
08424
08425 }
08426 if (!res && vms->oldmessages) {
08427 res = say_and_wait(chan, vms->oldmessages, chan->language);
08428 if (!res)
08429 res = ast_play_and_wait(chan, "vm-Old");
08430 if (!res) {
08431 if (vms->oldmessages == 1)
08432 res = ast_play_and_wait(chan, "vm-message");
08433 else
08434 res = ast_play_and_wait(chan, "vm-messages");
08435 }
08436 }
08437 if (!res) {
08438 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
08439 res = ast_play_and_wait(chan, "vm-no");
08440 if (!res)
08441 res = ast_play_and_wait(chan, "vm-messages");
08442 }
08443 }
08444 }
08445 return res;
08446 }
08447
08448
08449 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
08450 {
08451
08452 int res;
08453 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
08454 res = ast_play_and_wait(chan, "vm-no") ||
08455 ast_play_and_wait(chan, "vm-message");
08456 else
08457 res = ast_play_and_wait(chan, "vm-youhave");
08458 if (!res && vms->newmessages) {
08459 res = (vms->newmessages == 1) ?
08460 ast_play_and_wait(chan, "digits/un") ||
08461 ast_play_and_wait(chan, "vm-nuovo") ||
08462 ast_play_and_wait(chan, "vm-message") :
08463
08464 say_and_wait(chan, vms->newmessages, chan->language) ||
08465 ast_play_and_wait(chan, "vm-nuovi") ||
08466 ast_play_and_wait(chan, "vm-messages");
08467 if (!res && vms->oldmessages)
08468 res = ast_play_and_wait(chan, "vm-and");
08469 }
08470 if (!res && vms->oldmessages) {
08471 res = (vms->oldmessages == 1) ?
08472 ast_play_and_wait(chan, "digits/un") ||
08473 ast_play_and_wait(chan, "vm-vecchio") ||
08474 ast_play_and_wait(chan, "vm-message") :
08475
08476 say_and_wait(chan, vms->oldmessages, chan->language) ||
08477 ast_play_and_wait(chan, "vm-vecchi") ||
08478 ast_play_and_wait(chan, "vm-messages");
08479 }
08480 return res;
08481 }
08482
08483
08484 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
08485 {
08486
08487 int res;
08488 div_t num;
08489
08490 if (!vms->oldmessages && !vms->newmessages) {
08491 res = ast_play_and_wait(chan, "vm-no");
08492 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08493 return res;
08494 } else {
08495 res = ast_play_and_wait(chan, "vm-youhave");
08496 }
08497
08498 if (vms->newmessages) {
08499 num = div(vms->newmessages, 10);
08500 if (vms->newmessages == 1) {
08501 res = ast_play_and_wait(chan, "digits/1-a");
08502 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
08503 res = res ? res : ast_play_and_wait(chan, "vm-message");
08504 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08505 if (num.rem == 2) {
08506 if (!num.quot) {
08507 res = ast_play_and_wait(chan, "digits/2-ie");
08508 } else {
08509 res = say_and_wait(chan, vms->newmessages - 2 , chan->language);
08510 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08511 }
08512 } else {
08513 res = say_and_wait(chan, vms->newmessages, chan->language);
08514 }
08515 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
08516 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08517 } else {
08518 res = say_and_wait(chan, vms->newmessages, chan->language);
08519 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
08520 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08521 }
08522 if (!res && vms->oldmessages)
08523 res = ast_play_and_wait(chan, "vm-and");
08524 }
08525 if (!res && vms->oldmessages) {
08526 num = div(vms->oldmessages, 10);
08527 if (vms->oldmessages == 1) {
08528 res = ast_play_and_wait(chan, "digits/1-a");
08529 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
08530 res = res ? res : ast_play_and_wait(chan, "vm-message");
08531 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08532 if (num.rem == 2) {
08533 if (!num.quot) {
08534 res = ast_play_and_wait(chan, "digits/2-ie");
08535 } else {
08536 res = say_and_wait(chan, vms->oldmessages - 2 , chan->language);
08537 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08538 }
08539 } else {
08540 res = say_and_wait(chan, vms->oldmessages, chan->language);
08541 }
08542 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
08543 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08544 } else {
08545 res = say_and_wait(chan, vms->oldmessages, chan->language);
08546 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
08547 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08548 }
08549 }
08550
08551 return res;
08552 }
08553
08554
08555 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
08556 {
08557
08558 int res;
08559
08560 res = ast_play_and_wait(chan, "vm-youhave");
08561 if (res)
08562 return res;
08563
08564 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08565 res = ast_play_and_wait(chan, "vm-no");
08566 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08567 return res;
08568 }
08569
08570 if (vms->newmessages) {
08571 if ((vms->newmessages == 1)) {
08572 res = ast_play_and_wait(chan, "digits/ett");
08573 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
08574 res = res ? res : ast_play_and_wait(chan, "vm-message");
08575 } else {
08576 res = say_and_wait(chan, vms->newmessages, chan->language);
08577 res = res ? res : ast_play_and_wait(chan, "vm-nya");
08578 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08579 }
08580 if (!res && vms->oldmessages)
08581 res = ast_play_and_wait(chan, "vm-and");
08582 }
08583 if (!res && vms->oldmessages) {
08584 if (vms->oldmessages == 1) {
08585 res = ast_play_and_wait(chan, "digits/ett");
08586 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
08587 res = res ? res : ast_play_and_wait(chan, "vm-message");
08588 } else {
08589 res = say_and_wait(chan, vms->oldmessages, chan->language);
08590 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
08591 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08592 }
08593 }
08594
08595 return res;
08596 }
08597
08598
08599 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
08600 {
08601
08602 int res;
08603
08604 res = ast_play_and_wait(chan, "vm-youhave");
08605 if (res)
08606 return res;
08607
08608 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08609 res = ast_play_and_wait(chan, "vm-no");
08610 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08611 return res;
08612 }
08613
08614 if (vms->newmessages) {
08615 if ((vms->newmessages == 1)) {
08616 res = ast_play_and_wait(chan, "digits/1");
08617 res = res ? res : ast_play_and_wait(chan, "vm-ny");
08618 res = res ? res : ast_play_and_wait(chan, "vm-message");
08619 } else {
08620 res = say_and_wait(chan, vms->newmessages, chan->language);
08621 res = res ? res : ast_play_and_wait(chan, "vm-nye");
08622 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08623 }
08624 if (!res && vms->oldmessages)
08625 res = ast_play_and_wait(chan, "vm-and");
08626 }
08627 if (!res && vms->oldmessages) {
08628 if (vms->oldmessages == 1) {
08629 res = ast_play_and_wait(chan, "digits/1");
08630 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
08631 res = res ? res : ast_play_and_wait(chan, "vm-message");
08632 } else {
08633 res = say_and_wait(chan, vms->oldmessages, chan->language);
08634 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
08635 res = res ? res : ast_play_and_wait(chan, "vm-messages");
08636 }
08637 }
08638
08639 return res;
08640 }
08641
08642
08643 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
08644 {
08645
08646 int res;
08647 res = ast_play_and_wait(chan, "vm-youhave");
08648 if (!res) {
08649 if (vms->newmessages) {
08650 if ((vms->newmessages == 1))
08651 res = ast_play_and_wait(chan, "digits/1F");
08652 else
08653 res = say_and_wait(chan, vms->newmessages, chan->language);
08654 if (!res)
08655 res = ast_play_and_wait(chan, "vm-INBOX");
08656 if (vms->oldmessages && !res)
08657 res = ast_play_and_wait(chan, "vm-and");
08658 else if (!res) {
08659 if ((vms->newmessages == 1))
08660 res = ast_play_and_wait(chan, "vm-message");
08661 else
08662 res = ast_play_and_wait(chan, "vm-messages");
08663 }
08664
08665 }
08666 if (!res && vms->oldmessages) {
08667 if (vms->oldmessages == 1)
08668 res = ast_play_and_wait(chan, "digits/1F");
08669 else
08670 res = say_and_wait(chan, vms->oldmessages, chan->language);
08671 if (!res)
08672 res = ast_play_and_wait(chan, "vm-Old");
08673 if (!res) {
08674 if (vms->oldmessages == 1)
08675 res = ast_play_and_wait(chan, "vm-message");
08676 else
08677 res = ast_play_and_wait(chan, "vm-messages");
08678 }
08679 }
08680 if (!res) {
08681 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08682 res = ast_play_and_wait(chan, "vm-no");
08683 if (!res)
08684 res = ast_play_and_wait(chan, "vm-messages");
08685 }
08686 }
08687 }
08688 return res;
08689 }
08690
08691
08692 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
08693 {
08694
08695 int res;
08696 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08697 res = ast_play_and_wait(chan, "vm-youhaveno");
08698 if (!res)
08699 res = ast_play_and_wait(chan, "vm-messages");
08700 } else {
08701 res = ast_play_and_wait(chan, "vm-youhave");
08702 }
08703 if (!res) {
08704 if (vms->newmessages) {
08705 if (!res) {
08706 if ((vms->newmessages == 1)) {
08707 res = ast_play_and_wait(chan, "digits/1M");
08708 if (!res)
08709 res = ast_play_and_wait(chan, "vm-message");
08710 if (!res)
08711 res = ast_play_and_wait(chan, "vm-INBOXs");
08712 } else {
08713 res = say_and_wait(chan, vms->newmessages, chan->language);
08714 if (!res)
08715 res = ast_play_and_wait(chan, "vm-messages");
08716 if (!res)
08717 res = ast_play_and_wait(chan, "vm-INBOX");
08718 }
08719 }
08720 if (vms->oldmessages && !res)
08721 res = ast_play_and_wait(chan, "vm-and");
08722 }
08723 if (vms->oldmessages) {
08724 if (!res) {
08725 if (vms->oldmessages == 1) {
08726 res = ast_play_and_wait(chan, "digits/1M");
08727 if (!res)
08728 res = ast_play_and_wait(chan, "vm-message");
08729 if (!res)
08730 res = ast_play_and_wait(chan, "vm-Olds");
08731 } else {
08732 res = say_and_wait(chan, vms->oldmessages, chan->language);
08733 if (!res)
08734 res = ast_play_and_wait(chan, "vm-messages");
08735 if (!res)
08736 res = ast_play_and_wait(chan, "vm-Old");
08737 }
08738 }
08739 }
08740 }
08741 return res;
08742 }
08743
08744
08745 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
08746
08747 int res;
08748 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08749 res = ast_play_and_wait(chan, "vm-nomessages");
08750 return res;
08751 } else {
08752 res = ast_play_and_wait(chan, "vm-youhave");
08753 }
08754 if (vms->newmessages) {
08755 if (!res)
08756 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08757 if ((vms->newmessages == 1)) {
08758 if (!res)
08759 res = ast_play_and_wait(chan, "vm-message");
08760 if (!res)
08761 res = ast_play_and_wait(chan, "vm-INBOXs");
08762 } else {
08763 if (!res)
08764 res = ast_play_and_wait(chan, "vm-messages");
08765 if (!res)
08766 res = ast_play_and_wait(chan, "vm-INBOX");
08767 }
08768 if (vms->oldmessages && !res)
08769 res = ast_play_and_wait(chan, "vm-and");
08770 }
08771 if (vms->oldmessages) {
08772 if (!res)
08773 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08774 if (vms->oldmessages == 1) {
08775 if (!res)
08776 res = ast_play_and_wait(chan, "vm-message");
08777 if (!res)
08778 res = ast_play_and_wait(chan, "vm-Olds");
08779 } else {
08780 if (!res)
08781 res = ast_play_and_wait(chan, "vm-messages");
08782 if (!res)
08783 res = ast_play_and_wait(chan, "vm-Old");
08784 }
08785 }
08786 return res;
08787 }
08788
08789
08790 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
08791 {
08792
08793 int res;
08794 res = ast_play_and_wait(chan, "vm-youhave");
08795 if (!res) {
08796 if (vms->newmessages) {
08797 res = say_and_wait(chan, vms->newmessages, chan->language);
08798 if (!res)
08799 res = ast_play_and_wait(chan, "vm-INBOX");
08800 if (vms->oldmessages && !res)
08801 res = ast_play_and_wait(chan, "vm-and");
08802 else if (!res) {
08803 if ((vms->newmessages == 1))
08804 res = ast_play_and_wait(chan, "vm-message");
08805 else
08806 res = ast_play_and_wait(chan, "vm-messages");
08807 }
08808
08809 }
08810 if (!res && vms->oldmessages) {
08811 res = say_and_wait(chan, vms->oldmessages, chan->language);
08812 if (!res)
08813 res = ast_play_and_wait(chan, "vm-Old");
08814 if (!res) {
08815 if (vms->oldmessages == 1)
08816 res = ast_play_and_wait(chan, "vm-message");
08817 else
08818 res = ast_play_and_wait(chan, "vm-messages");
08819 }
08820 }
08821 if (!res) {
08822 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08823 res = ast_play_and_wait(chan, "vm-no");
08824 if (!res)
08825 res = ast_play_and_wait(chan, "vm-messages");
08826 }
08827 }
08828 }
08829 return res;
08830 }
08831
08832
08833 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
08834 {
08835
08836 int res;
08837 res = ast_play_and_wait(chan, "vm-youhave");
08838 if (!res) {
08839 if (vms->newmessages) {
08840 res = say_and_wait(chan, vms->newmessages, chan->language);
08841 if (!res) {
08842 if (vms->newmessages == 1)
08843 res = ast_play_and_wait(chan, "vm-INBOXs");
08844 else
08845 res = ast_play_and_wait(chan, "vm-INBOX");
08846 }
08847 if (vms->oldmessages && !res)
08848 res = ast_play_and_wait(chan, "vm-and");
08849 else if (!res) {
08850 if ((vms->newmessages == 1))
08851 res = ast_play_and_wait(chan, "vm-message");
08852 else
08853 res = ast_play_and_wait(chan, "vm-messages");
08854 }
08855
08856 }
08857 if (!res && vms->oldmessages) {
08858 res = say_and_wait(chan, vms->oldmessages, chan->language);
08859 if (!res) {
08860 if (vms->oldmessages == 1)
08861 res = ast_play_and_wait(chan, "vm-Olds");
08862 else
08863 res = ast_play_and_wait(chan, "vm-Old");
08864 }
08865 if (!res) {
08866 if (vms->oldmessages == 1)
08867 res = ast_play_and_wait(chan, "vm-message");
08868 else
08869 res = ast_play_and_wait(chan, "vm-messages");
08870 }
08871 }
08872 if (!res) {
08873 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08874 res = ast_play_and_wait(chan, "vm-no");
08875 if (!res)
08876 res = ast_play_and_wait(chan, "vm-messages");
08877 }
08878 }
08879 }
08880 return res;
08881 }
08882
08883
08884 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
08885 {
08886
08887 int res;
08888 res = ast_play_and_wait(chan, "vm-youhave");
08889 if (!res) {
08890 if (vms->newmessages) {
08891 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, chan->language, "f");
08892 if (!res) {
08893 if ((vms->newmessages == 1)) {
08894 res = ast_play_and_wait(chan, "vm-message");
08895 if (!res)
08896 res = ast_play_and_wait(chan, "vm-INBOXs");
08897 } else {
08898 res = ast_play_and_wait(chan, "vm-messages");
08899 if (!res)
08900 res = ast_play_and_wait(chan, "vm-INBOX");
08901 }
08902 }
08903 if (vms->oldmessages && !res)
08904 res = ast_play_and_wait(chan, "vm-and");
08905 }
08906 if (!res && vms->oldmessages) {
08907 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, chan->language, "f");
08908 if (!res) {
08909 if (vms->oldmessages == 1) {
08910 res = ast_play_and_wait(chan, "vm-message");
08911 if (!res)
08912 res = ast_play_and_wait(chan, "vm-Olds");
08913 } else {
08914 res = ast_play_and_wait(chan, "vm-messages");
08915 if (!res)
08916 res = ast_play_and_wait(chan, "vm-Old");
08917 }
08918 }
08919 }
08920 if (!res) {
08921 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08922 res = ast_play_and_wait(chan, "vm-no");
08923 if (!res)
08924 res = ast_play_and_wait(chan, "vm-messages");
08925 }
08926 }
08927 }
08928 return res;
08929 }
08930
08931
08932
08933
08934
08935
08936
08937
08938
08939
08940
08941
08942
08943
08944
08945
08946
08947 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
08948 {
08949 int res;
08950 res = ast_play_and_wait(chan, "vm-youhave");
08951 if (!res) {
08952 if (vms->newmessages) {
08953 if (vms->newmessages == 1) {
08954 res = ast_play_and_wait(chan, "digits/jednu");
08955 } else {
08956 res = say_and_wait(chan, vms->newmessages, chan->language);
08957 }
08958 if (!res) {
08959 if ((vms->newmessages == 1))
08960 res = ast_play_and_wait(chan, "vm-novou");
08961 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08962 res = ast_play_and_wait(chan, "vm-nove");
08963 if (vms->newmessages > 4)
08964 res = ast_play_and_wait(chan, "vm-novych");
08965 }
08966 if (vms->oldmessages && !res)
08967 res = ast_play_and_wait(chan, "vm-and");
08968 else if (!res) {
08969 if ((vms->newmessages == 1))
08970 res = ast_play_and_wait(chan, "vm-zpravu");
08971 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
08972 res = ast_play_and_wait(chan, "vm-zpravy");
08973 if (vms->newmessages > 4)
08974 res = ast_play_and_wait(chan, "vm-zprav");
08975 }
08976 }
08977 if (!res && vms->oldmessages) {
08978 res = say_and_wait(chan, vms->oldmessages, chan->language);
08979 if (!res) {
08980 if ((vms->oldmessages == 1))
08981 res = ast_play_and_wait(chan, "vm-starou");
08982 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08983 res = ast_play_and_wait(chan, "vm-stare");
08984 if (vms->oldmessages > 4)
08985 res = ast_play_and_wait(chan, "vm-starych");
08986 }
08987 if (!res) {
08988 if ((vms->oldmessages == 1))
08989 res = ast_play_and_wait(chan, "vm-zpravu");
08990 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
08991 res = ast_play_and_wait(chan, "vm-zpravy");
08992 if (vms->oldmessages > 4)
08993 res = ast_play_and_wait(chan, "vm-zprav");
08994 }
08995 }
08996 if (!res) {
08997 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
08998 res = ast_play_and_wait(chan, "vm-no");
08999 if (!res)
09000 res = ast_play_and_wait(chan, "vm-zpravy");
09001 }
09002 }
09003 }
09004 return res;
09005 }
09006
09007
09008 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
09009 {
09010 int res;
09011
09012 res = ast_play_and_wait(chan, "vm-you");
09013
09014 if (!res && vms->newmessages) {
09015 res = ast_play_and_wait(chan, "vm-have");
09016 if (!res)
09017 res = say_and_wait(chan, vms->newmessages, chan->language);
09018 if (!res)
09019 res = ast_play_and_wait(chan, "vm-tong");
09020 if (!res)
09021 res = ast_play_and_wait(chan, "vm-INBOX");
09022 if (vms->oldmessages && !res)
09023 res = ast_play_and_wait(chan, "vm-and");
09024 else if (!res)
09025 res = ast_play_and_wait(chan, "vm-messages");
09026 }
09027 if (!res && vms->oldmessages) {
09028 res = ast_play_and_wait(chan, "vm-have");
09029 if (!res)
09030 res = say_and_wait(chan, vms->oldmessages, chan->language);
09031 if (!res)
09032 res = ast_play_and_wait(chan, "vm-tong");
09033 if (!res)
09034 res = ast_play_and_wait(chan, "vm-Old");
09035 if (!res)
09036 res = ast_play_and_wait(chan, "vm-messages");
09037 }
09038 if (!res && !vms->oldmessages && !vms->newmessages) {
09039 res = ast_play_and_wait(chan, "vm-haveno");
09040 if (!res)
09041 res = ast_play_and_wait(chan, "vm-messages");
09042 }
09043 return res;
09044 }
09045
09046
09047 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
09048 {
09049 int res;
09050
09051
09052 res = ast_play_and_wait(chan, "vm-youhave");
09053 if (!res) {
09054 if (vms->newmessages) {
09055 res = say_and_wait(chan, vms->newmessages, chan->language);
09056 if (!res)
09057 res = ast_play_and_wait(chan, "vm-INBOX");
09058 if (vms->oldmessages && !res)
09059 res = ast_play_and_wait(chan, "vm-and");
09060 }
09061 if (!res && vms->oldmessages) {
09062 res = say_and_wait(chan, vms->oldmessages, chan->language);
09063 if (!res)
09064 res = ast_play_and_wait(chan, "vm-Old");
09065 }
09066 if (!res) {
09067 if (!vms->oldmessages && !vms->newmessages) {
09068 res = ast_play_and_wait(chan, "vm-no");
09069 if (!res)
09070 res = ast_play_and_wait(chan, "vm-message");
09071 }
09072 }
09073 }
09074 return res;
09075 }
09076
09077 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
09078 {
09079 char prefile[256];
09080
09081
09082 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09083 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
09084 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09085 if (ast_fileexists(prefile, NULL, NULL) > 0) {
09086 ast_play_and_wait(chan, "vm-tempgreetactive");
09087 }
09088 DISPOSE(prefile, -1);
09089 }
09090
09091
09092 if (0) {
09093 return 0;
09094 } else if (!strncasecmp(chan->language, "cs", 2)) {
09095 return vm_intro_cs(chan, vms);
09096 } else if (!strncasecmp(chan->language, "cz", 2)) {
09097 static int deprecation_warning = 0;
09098 if (deprecation_warning++ % 10 == 0) {
09099 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09100 }
09101 return vm_intro_cs(chan, vms);
09102 } else if (!strncasecmp(chan->language, "de", 2)) {
09103 return vm_intro_de(chan, vms);
09104 } else if (!strncasecmp(chan->language, "es", 2)) {
09105 return vm_intro_es(chan, vms);
09106 } else if (!strncasecmp(chan->language, "fr", 2)) {
09107 return vm_intro_fr(chan, vms);
09108 } else if (!strncasecmp(chan->language, "gr", 2)) {
09109 return vm_intro_gr(chan, vms);
09110 } else if (!strncasecmp(chan->language, "he", 2)) {
09111 return vm_intro_he(chan, vms);
09112 } else if (!strncasecmp(chan->language, "it", 2)) {
09113 return vm_intro_it(chan, vms);
09114 } else if (!strncasecmp(chan->language, "nl", 2)) {
09115 return vm_intro_nl(chan, vms);
09116 } else if (!strncasecmp(chan->language, "no", 2)) {
09117 return vm_intro_no(chan, vms);
09118 } else if (!strncasecmp(chan->language, "pl", 2)) {
09119 return vm_intro_pl(chan, vms);
09120 } else if (!strncasecmp(chan->language, "pt_BR", 5)) {
09121 return vm_intro_pt_BR(chan, vms);
09122 } else if (!strncasecmp(chan->language, "pt", 2)) {
09123 return vm_intro_pt(chan, vms);
09124 } else if (!strncasecmp(chan->language, "ru", 2)) {
09125 return vm_intro_multilang(chan, vms, "n");
09126 } else if (!strncasecmp(chan->language, "se", 2)) {
09127 return vm_intro_se(chan, vms);
09128 } else if (!strncasecmp(chan->language, "ua", 2)) {
09129 return vm_intro_multilang(chan, vms, "n");
09130 } else if (!strncasecmp(chan->language, "vi", 2)) {
09131 return vm_intro_vi(chan, vms);
09132 } else if (!strncasecmp(chan->language, "zh", 2)) {
09133 return vm_intro_zh(chan, vms);
09134 } else {
09135 return vm_intro_en(chan, vms);
09136 }
09137 }
09138
09139 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09140 {
09141 int res = 0;
09142
09143 while (!res) {
09144 if (vms->starting) {
09145 if (vms->lastmsg > -1) {
09146 if (skipadvanced)
09147 res = ast_play_and_wait(chan, "vm-onefor-full");
09148 else
09149 res = ast_play_and_wait(chan, "vm-onefor");
09150 if (!res)
09151 res = vm_play_folder_name(chan, vms->vmbox);
09152 }
09153 if (!res) {
09154 if (skipadvanced)
09155 res = ast_play_and_wait(chan, "vm-opts-full");
09156 else
09157 res = ast_play_and_wait(chan, "vm-opts");
09158 }
09159 } else {
09160
09161 if (skipadvanced) {
09162 res = ast_play_and_wait(chan, "vm-onefor-full");
09163 if (!res)
09164 res = vm_play_folder_name(chan, vms->vmbox);
09165 res = ast_play_and_wait(chan, "vm-opts-full");
09166 }
09167
09168
09169
09170
09171
09172
09173 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09174 res = ast_play_and_wait(chan, "vm-prev");
09175 }
09176 if (!res && !skipadvanced)
09177 res = ast_play_and_wait(chan, "vm-advopts");
09178 if (!res)
09179 res = ast_play_and_wait(chan, "vm-repeat");
09180
09181
09182
09183
09184
09185
09186 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09187 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09188 res = ast_play_and_wait(chan, "vm-next");
09189 }
09190 if (!res) {
09191 int curmsg_deleted;
09192 #ifdef IMAP_STORAGE
09193 ast_mutex_lock(&vms->lock);
09194 #endif
09195 curmsg_deleted = vms->deleted[vms->curmsg];
09196 #ifdef IMAP_STORAGE
09197 ast_mutex_unlock(&vms->lock);
09198 #endif
09199 if (!curmsg_deleted) {
09200 res = ast_play_and_wait(chan, "vm-delete");
09201 } else {
09202 res = ast_play_and_wait(chan, "vm-undelete");
09203 }
09204 if (!res) {
09205 res = ast_play_and_wait(chan, "vm-toforward");
09206 }
09207 if (!res) {
09208 res = ast_play_and_wait(chan, "vm-savemessage");
09209 }
09210 }
09211 }
09212 if (!res) {
09213 res = ast_play_and_wait(chan, "vm-helpexit");
09214 }
09215 if (!res)
09216 res = ast_waitfordigit(chan, 6000);
09217 if (!res) {
09218 vms->repeats++;
09219 if (vms->repeats > 2) {
09220 res = 't';
09221 }
09222 }
09223 }
09224 return res;
09225 }
09226
09227 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09228 {
09229 int res = 0;
09230
09231 while (!res) {
09232 if (vms->lastmsg > -1) {
09233 res = ast_play_and_wait(chan, "vm-listen");
09234 if (!res)
09235 res = vm_play_folder_name(chan, vms->vmbox);
09236 if (!res)
09237 res = ast_play_and_wait(chan, "press");
09238 if (!res)
09239 res = ast_play_and_wait(chan, "digits/1");
09240 }
09241 if (!res)
09242 res = ast_play_and_wait(chan, "vm-opts");
09243 if (!res) {
09244 vms->starting = 0;
09245 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09246 }
09247 }
09248 return res;
09249 }
09250
09251 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09252 {
09253 if (vms->starting && !strncasecmp(chan->language, "zh", 2)) {
09254 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09255 } else {
09256 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09257 }
09258 }
09259
09260
09261 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09262 {
09263 int cmd = 0;
09264 int duration = 0;
09265 int tries = 0;
09266 char newpassword[80] = "";
09267 char newpassword2[80] = "";
09268 char prefile[PATH_MAX] = "";
09269 unsigned char buf[256];
09270 int bytes = 0;
09271
09272 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09273 if (ast_adsi_available(chan)) {
09274 bytes += adsi_logo(buf + bytes);
09275 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09276 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09277 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09278 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09279 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09280 }
09281
09282
09283 if (ast_test_flag(vmu, VM_FORCENAME)) {
09284 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09285 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09286 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09287 if (cmd < 0 || cmd == 't' || cmd == '#')
09288 return cmd;
09289 }
09290 }
09291
09292
09293 if (ast_test_flag(vmu, VM_FORCEGREET)) {
09294 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09295 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09296 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09297 if (cmd < 0 || cmd == 't' || cmd == '#')
09298 return cmd;
09299 }
09300
09301 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09302 if (ast_fileexists(prefile, NULL, NULL) < 1) {
09303 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09304 if (cmd < 0 || cmd == 't' || cmd == '#')
09305 return cmd;
09306 }
09307 }
09308
09309
09310
09311
09312
09313 for (;;) {
09314 newpassword[1] = '\0';
09315 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09316 if (cmd == '#')
09317 newpassword[0] = '\0';
09318 if (cmd < 0 || cmd == 't' || cmd == '#')
09319 return cmd;
09320 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
09321 if (cmd < 0 || cmd == 't' || cmd == '#')
09322 return cmd;
09323 cmd = check_password(vmu, newpassword);
09324 if (cmd != 0) {
09325 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09326 cmd = ast_play_and_wait(chan, vm_invalid_password);
09327 } else {
09328 newpassword2[1] = '\0';
09329 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09330 if (cmd == '#')
09331 newpassword2[0] = '\0';
09332 if (cmd < 0 || cmd == 't' || cmd == '#')
09333 return cmd;
09334 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
09335 if (cmd < 0 || cmd == 't' || cmd == '#')
09336 return cmd;
09337 if (!strcmp(newpassword, newpassword2))
09338 break;
09339 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09340 cmd = ast_play_and_wait(chan, vm_mismatch);
09341 }
09342 if (++tries == 3)
09343 return -1;
09344 if (cmd != 0) {
09345 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09346 }
09347 }
09348 if (pwdchange & PWDCHANGE_INTERNAL)
09349 vm_change_password(vmu, newpassword);
09350 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
09351 vm_change_password_shell(vmu, newpassword);
09352
09353 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
09354 cmd = ast_play_and_wait(chan, vm_passchanged);
09355
09356 return cmd;
09357 }
09358
09359 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09360 {
09361 int cmd = 0;
09362 int retries = 0;
09363 int duration = 0;
09364 char newpassword[80] = "";
09365 char newpassword2[80] = "";
09366 char prefile[PATH_MAX] = "";
09367 unsigned char buf[256];
09368 int bytes = 0;
09369
09370 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
09371 if (ast_adsi_available(chan)) {
09372 bytes += adsi_logo(buf + bytes);
09373 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
09374 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09375 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09376 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09377 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09378 }
09379 while ((cmd >= 0) && (cmd != 't')) {
09380 if (cmd)
09381 retries = 0;
09382 switch (cmd) {
09383 case '1':
09384 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
09385 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09386 break;
09387 case '2':
09388 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
09389 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09390 break;
09391 case '3':
09392 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09393 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09394 break;
09395 case '4':
09396 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
09397 break;
09398 case '5':
09399 if (vmu->password[0] == '-') {
09400 cmd = ast_play_and_wait(chan, "vm-no");
09401 break;
09402 }
09403 newpassword[1] = '\0';
09404 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
09405 if (cmd == '#')
09406 newpassword[0] = '\0';
09407 else {
09408 if (cmd < 0)
09409 break;
09410 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
09411 break;
09412 }
09413 }
09414 cmd = check_password(vmu, newpassword);
09415 if (cmd != 0) {
09416 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
09417 cmd = ast_play_and_wait(chan, vm_invalid_password);
09418 if (!cmd) {
09419 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09420 }
09421 break;
09422 }
09423 newpassword2[1] = '\0';
09424 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
09425 if (cmd == '#')
09426 newpassword2[0] = '\0';
09427 else {
09428 if (cmd < 0)
09429 break;
09430
09431 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
09432 break;
09433 }
09434 }
09435 if (strcmp(newpassword, newpassword2)) {
09436 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
09437 cmd = ast_play_and_wait(chan, vm_mismatch);
09438 if (!cmd) {
09439 cmd = ast_play_and_wait(chan, vm_pls_try_again);
09440 }
09441 break;
09442 }
09443
09444 if (pwdchange & PWDCHANGE_INTERNAL) {
09445 vm_change_password(vmu, newpassword);
09446 }
09447 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
09448 vm_change_password_shell(vmu, newpassword);
09449 }
09450
09451 ast_debug(1, "User %s set password to %s of length %d\n",
09452 vms->username, newpassword, (int) strlen(newpassword));
09453 cmd = ast_play_and_wait(chan, vm_passchanged);
09454 break;
09455 case '*':
09456 cmd = 't';
09457 break;
09458 default:
09459 cmd = 0;
09460 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09461 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09462 if (ast_fileexists(prefile, NULL, NULL)) {
09463 cmd = ast_play_and_wait(chan, "vm-tmpexists");
09464 }
09465 DISPOSE(prefile, -1);
09466 if (!cmd) {
09467 cmd = ast_play_and_wait(chan, "vm-options");
09468 }
09469 if (!cmd) {
09470 cmd = ast_waitfordigit(chan, 6000);
09471 }
09472 if (!cmd) {
09473 retries++;
09474 }
09475 if (retries > 3) {
09476 cmd = 't';
09477 }
09478 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09479 }
09480 }
09481 if (cmd == 't')
09482 cmd = 0;
09483 return cmd;
09484 }
09485
09486
09487
09488
09489
09490
09491
09492
09493
09494
09495
09496
09497
09498
09499
09500
09501
09502 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09503 {
09504 int cmd = 0;
09505 int retries = 0;
09506 int duration = 0;
09507 char prefile[PATH_MAX] = "";
09508 unsigned char buf[256];
09509 int bytes = 0;
09510
09511 if (ast_adsi_available(chan)) {
09512 bytes += adsi_logo(buf + bytes);
09513 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
09514 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09515 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09516 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09517 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09518 }
09519
09520 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
09521 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09522 while ((cmd >= 0) && (cmd != 't')) {
09523 if (cmd)
09524 retries = 0;
09525 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09526 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
09527 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09528 if (cmd == -1) {
09529 break;
09530 }
09531 cmd = 't';
09532 } else {
09533 switch (cmd) {
09534 case '1':
09535 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
09536 break;
09537 case '2':
09538 DELETE(prefile, -1, prefile, vmu);
09539 ast_play_and_wait(chan, "vm-tempremoved");
09540 cmd = 't';
09541 break;
09542 case '*':
09543 cmd = 't';
09544 break;
09545 default:
09546 cmd = ast_play_and_wait(chan,
09547 ast_fileexists(prefile, NULL, NULL) > 0 ?
09548 "vm-tempgreeting2" : "vm-tempgreeting");
09549 if (!cmd) {
09550 cmd = ast_waitfordigit(chan, 6000);
09551 }
09552 if (!cmd) {
09553 retries++;
09554 }
09555 if (retries > 3) {
09556 cmd = 't';
09557 }
09558 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
09559 }
09560 }
09561 DISPOSE(prefile, -1);
09562 }
09563 if (cmd == 't')
09564 cmd = 0;
09565 return cmd;
09566 }
09567
09568
09569
09570
09571
09572
09573
09574
09575
09576 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09577 {
09578 int cmd = 0;
09579
09580 if (vms->lastmsg > -1) {
09581 cmd = play_message(chan, vmu, vms);
09582 } else {
09583 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09584 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
09585 if (!cmd) {
09586 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
09587 cmd = ast_play_and_wait(chan, vms->fn);
09588 }
09589 if (!cmd)
09590 cmd = ast_play_and_wait(chan, "vm-messages");
09591 } else {
09592 if (!cmd)
09593 cmd = ast_play_and_wait(chan, "vm-messages");
09594 if (!cmd) {
09595 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09596 cmd = ast_play_and_wait(chan, vms->fn);
09597 }
09598 }
09599 }
09600 return cmd;
09601 }
09602
09603
09604 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09605 {
09606 int cmd = 0;
09607
09608 if (vms->lastmsg > -1) {
09609 cmd = play_message(chan, vmu, vms);
09610 } else {
09611 if (!strcasecmp(vms->fn, "INBOX")) {
09612 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
09613 } else {
09614 cmd = ast_play_and_wait(chan, "vm-nomessages");
09615 }
09616 }
09617 return cmd;
09618 }
09619
09620
09621
09622
09623
09624
09625
09626
09627
09628 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09629 {
09630 int cmd = 0;
09631
09632 if (vms->lastmsg > -1) {
09633 cmd = play_message(chan, vmu, vms);
09634 } else {
09635 cmd = ast_play_and_wait(chan, "vm-youhave");
09636 if (!cmd)
09637 cmd = ast_play_and_wait(chan, "vm-no");
09638 if (!cmd) {
09639 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09640 cmd = ast_play_and_wait(chan, vms->fn);
09641 }
09642 if (!cmd)
09643 cmd = ast_play_and_wait(chan, "vm-messages");
09644 }
09645 return cmd;
09646 }
09647
09648
09649
09650
09651
09652
09653
09654
09655
09656 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09657 {
09658 int cmd;
09659
09660 if (vms->lastmsg > -1) {
09661 cmd = play_message(chan, vmu, vms);
09662 } else {
09663 cmd = ast_play_and_wait(chan, "vm-no");
09664 if (!cmd)
09665 cmd = ast_play_and_wait(chan, "vm-message");
09666 if (!cmd) {
09667 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09668 cmd = ast_play_and_wait(chan, vms->fn);
09669 }
09670 }
09671 return cmd;
09672 }
09673
09674
09675
09676
09677
09678
09679
09680
09681
09682 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09683 {
09684 int cmd;
09685
09686 if (vms->lastmsg > -1) {
09687 cmd = play_message(chan, vmu, vms);
09688 } else {
09689 cmd = ast_play_and_wait(chan, "vm-youhaveno");
09690 if (!cmd)
09691 cmd = ast_play_and_wait(chan, "vm-messages");
09692 if (!cmd) {
09693 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09694 cmd = ast_play_and_wait(chan, vms->fn);
09695 }
09696 }
09697 return cmd;
09698 }
09699
09700
09701
09702
09703
09704
09705
09706
09707
09708 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09709 {
09710 int cmd;
09711
09712 if (vms->lastmsg > -1) {
09713 cmd = play_message(chan, vmu, vms);
09714 } else {
09715 cmd = ast_play_and_wait(chan, "vm-no");
09716 if (!cmd) {
09717 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09718 cmd = ast_play_and_wait(chan, vms->fn);
09719 }
09720 if (!cmd)
09721 cmd = ast_play_and_wait(chan, "vm-messages");
09722 }
09723 return cmd;
09724 }
09725
09726
09727
09728
09729
09730
09731
09732
09733
09734 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09735 {
09736 int cmd;
09737
09738 if (vms->lastmsg > -1) {
09739 cmd = play_message(chan, vmu, vms);
09740 } else {
09741 cmd = ast_play_and_wait(chan, "vm-you");
09742 if (!cmd)
09743 cmd = ast_play_and_wait(chan, "vm-haveno");
09744 if (!cmd)
09745 cmd = ast_play_and_wait(chan, "vm-messages");
09746 if (!cmd) {
09747 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09748 cmd = ast_play_and_wait(chan, vms->fn);
09749 }
09750 }
09751 return cmd;
09752 }
09753
09754
09755
09756
09757
09758
09759
09760
09761
09762 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09763 {
09764 int cmd = 0;
09765
09766 if (vms->lastmsg > -1) {
09767 cmd = play_message(chan, vmu, vms);
09768 } else {
09769 cmd = ast_play_and_wait(chan, "vm-no");
09770 if (!cmd) {
09771 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
09772 cmd = ast_play_and_wait(chan, vms->fn);
09773 }
09774 }
09775 return cmd;
09776 }
09777
09778
09779
09780
09781
09782
09783
09784
09785
09786
09787
09788
09789 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
09790 {
09791 if (!strncasecmp(chan->language, "es", 2)) {
09792 return vm_browse_messages_es(chan, vms, vmu);
09793 } else if (!strncasecmp(chan->language, "gr", 2)) {
09794 return vm_browse_messages_gr(chan, vms, vmu);
09795 } else if (!strncasecmp(chan->language, "he", 2)) {
09796 return vm_browse_messages_he(chan, vms, vmu);
09797 } else if (!strncasecmp(chan->language, "it", 2)) {
09798 return vm_browse_messages_it(chan, vms, vmu);
09799 } else if (!strncasecmp(chan->language, "pt", 2)) {
09800 return vm_browse_messages_pt(chan, vms, vmu);
09801 } else if (!strncasecmp(chan->language, "vi", 2)) {
09802 return vm_browse_messages_vi(chan, vms, vmu);
09803 } else if (!strncasecmp(chan->language, "zh", 2)) {
09804 return vm_browse_messages_zh(chan, vms, vmu);
09805 } else {
09806 return vm_browse_messages_en(chan, vms, vmu);
09807 }
09808 }
09809
09810 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
09811 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
09812 int skipuser, int max_logins, int silent)
09813 {
09814 int useadsi = 0, valid = 0, logretries = 0;
09815 char password[AST_MAX_EXTENSION]="", *passptr;
09816 struct ast_vm_user vmus, *vmu = NULL;
09817
09818
09819 adsi_begin(chan, &useadsi);
09820 if (!skipuser && useadsi)
09821 adsi_login(chan);
09822 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", chan->language)) {
09823 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
09824 return -1;
09825 }
09826
09827
09828
09829 while (!valid && (logretries < max_logins)) {
09830
09831 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
09832 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
09833 return -1;
09834 }
09835 if (ast_strlen_zero(mailbox)) {
09836 if (chan->caller.id.number.valid && chan->caller.id.number.str) {
09837 ast_copy_string(mailbox, chan->caller.id.number.str, mailbox_size);
09838 } else {
09839 ast_verb(3, "Username not entered\n");
09840 return -1;
09841 }
09842 } else if (mailbox[0] == '*') {
09843
09844 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
09845 if (ast_exists_extension(chan, chan->context, "a", 1,
09846 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09847 return -1;
09848 }
09849 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
09850 mailbox[0] = '\0';
09851 }
09852
09853 if (useadsi)
09854 adsi_password(chan);
09855
09856 if (!ast_strlen_zero(prefix)) {
09857 char fullusername[80] = "";
09858 ast_copy_string(fullusername, prefix, sizeof(fullusername));
09859 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
09860 ast_copy_string(mailbox, fullusername, mailbox_size);
09861 }
09862
09863 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
09864 vmu = find_user(&vmus, context, mailbox);
09865 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
09866
09867 password[0] = '\0';
09868 } else {
09869 if (ast_streamfile(chan, vm_password, chan->language)) {
09870 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
09871 return -1;
09872 }
09873 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
09874 ast_log(AST_LOG_WARNING, "Unable to read password\n");
09875 return -1;
09876 } else if (password[0] == '*') {
09877
09878 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
09879 if (ast_exists_extension(chan, chan->context, "a", 1,
09880 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
09881 mailbox[0] = '*';
09882 return -1;
09883 }
09884 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
09885 mailbox[0] = '\0';
09886
09887 vmu = NULL;
09888 }
09889 }
09890
09891 if (vmu) {
09892 passptr = vmu->password;
09893 if (passptr[0] == '-') passptr++;
09894 }
09895 if (vmu && !strcmp(passptr, password))
09896 valid++;
09897 else {
09898 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
09899 if (!ast_strlen_zero(prefix))
09900 mailbox[0] = '\0';
09901 }
09902 logretries++;
09903 if (!valid) {
09904 if (skipuser || logretries >= max_logins) {
09905 if (ast_streamfile(chan, "vm-incorrect", chan->language)) {
09906 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
09907 return -1;
09908 }
09909 } else {
09910 if (useadsi)
09911 adsi_login(chan);
09912 if (ast_streamfile(chan, "vm-incorrect-mailbox", chan->language)) {
09913 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
09914 return -1;
09915 }
09916 }
09917 if (ast_waitstream(chan, ""))
09918 return -1;
09919 }
09920 }
09921 if (!valid && (logretries >= max_logins)) {
09922 ast_stopstream(chan);
09923 ast_play_and_wait(chan, "vm-goodbye");
09924 return -1;
09925 }
09926 if (vmu && !skipuser) {
09927 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
09928 }
09929 return 0;
09930 }
09931
09932 static int vm_execmain(struct ast_channel *chan, const char *data)
09933 {
09934
09935
09936
09937 int res = -1;
09938 int cmd = 0;
09939 int valid = 0;
09940 char prefixstr[80] ="";
09941 char ext_context[256]="";
09942 int box;
09943 int useadsi = 0;
09944 int skipuser = 0;
09945 struct vm_state vms;
09946 struct ast_vm_user *vmu = NULL, vmus;
09947 char *context = NULL;
09948 int silentexit = 0;
09949 struct ast_flags flags = { 0 };
09950 signed char record_gain = 0;
09951 int play_auto = 0;
09952 int play_folder = 0;
09953 int in_urgent = 0;
09954 #ifdef IMAP_STORAGE
09955 int deleted = 0;
09956 #endif
09957
09958
09959 memset(&vms, 0, sizeof(vms));
09960
09961 vms.lastmsg = -1;
09962
09963 memset(&vmus, 0, sizeof(vmus));
09964
09965 ast_test_suite_event_notify("START", "Message: vm_execmain started");
09966 if (chan->_state != AST_STATE_UP) {
09967 ast_debug(1, "Before ast_answer\n");
09968 ast_answer(chan);
09969 }
09970
09971 if (!ast_strlen_zero(data)) {
09972 char *opts[OPT_ARG_ARRAY_SIZE];
09973 char *parse;
09974 AST_DECLARE_APP_ARGS(args,
09975 AST_APP_ARG(argv0);
09976 AST_APP_ARG(argv1);
09977 );
09978
09979 parse = ast_strdupa(data);
09980
09981 AST_STANDARD_APP_ARGS(args, parse);
09982
09983 if (args.argc == 2) {
09984 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
09985 return -1;
09986 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
09987 int gain;
09988 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
09989 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
09990 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
09991 return -1;
09992 } else {
09993 record_gain = (signed char) gain;
09994 }
09995 } else {
09996 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
09997 }
09998 }
09999 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
10000 play_auto = 1;
10001 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
10002
10003 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
10004 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
10005 play_folder = -1;
10006 }
10007 } else {
10008 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
10009 }
10010 } else {
10011 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
10012 }
10013 if (play_folder > 9 || play_folder < 0) {
10014 ast_log(AST_LOG_WARNING,
10015 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
10016 opts[OPT_ARG_PLAYFOLDER]);
10017 play_folder = 0;
10018 }
10019 }
10020 } else {
10021
10022 while (*(args.argv0)) {
10023 if (*(args.argv0) == 's')
10024 ast_set_flag(&flags, OPT_SILENT);
10025 else if (*(args.argv0) == 'p')
10026 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
10027 else
10028 break;
10029 (args.argv0)++;
10030 }
10031
10032 }
10033
10034 valid = ast_test_flag(&flags, OPT_SILENT);
10035
10036 if ((context = strchr(args.argv0, '@')))
10037 *context++ = '\0';
10038
10039 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
10040 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
10041 else
10042 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
10043
10044 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
10045 skipuser++;
10046 else
10047 valid = 0;
10048 }
10049
10050 if (!valid)
10051 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
10052
10053 ast_debug(1, "After vm_authenticate\n");
10054
10055 if (vms.username[0] == '*') {
10056 ast_debug(1, "user pressed * in context '%s'\n", chan->context);
10057
10058
10059 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
10060 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
10061 res = 0;
10062 goto out;
10063 }
10064 }
10065
10066 if (!res) {
10067 valid = 1;
10068 if (!skipuser)
10069 vmu = &vmus;
10070 } else {
10071 res = 0;
10072 }
10073
10074
10075 adsi_begin(chan, &useadsi);
10076
10077 ast_test_suite_assert(valid);
10078 if (!valid) {
10079 goto out;
10080 }
10081 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
10082
10083 #ifdef IMAP_STORAGE
10084 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10085 pthread_setspecific(ts_vmstate.key, &vms);
10086
10087 vms.interactive = 1;
10088 vms.updated = 1;
10089 if (vmu)
10090 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10091 vmstate_insert(&vms);
10092 init_vm_state(&vms);
10093 #endif
10094
10095
10096 if (!ast_strlen_zero(vmu->language))
10097 ast_string_field_set(chan, language, vmu->language);
10098
10099
10100 ast_debug(1, "Before open_mailbox\n");
10101 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10102 if (res < 0)
10103 goto out;
10104 vms.oldmessages = vms.lastmsg + 1;
10105 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10106
10107 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10108 if (res < 0)
10109 goto out;
10110 vms.newmessages = vms.lastmsg + 1;
10111 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10112
10113 in_urgent = 1;
10114 res = open_mailbox(&vms, vmu, 11);
10115 if (res < 0)
10116 goto out;
10117 vms.urgentmessages = vms.lastmsg + 1;
10118 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10119
10120
10121 if (play_auto) {
10122 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10123 if (vms.urgentmessages) {
10124 in_urgent = 1;
10125 res = open_mailbox(&vms, vmu, 11);
10126 } else {
10127 in_urgent = 0;
10128 res = open_mailbox(&vms, vmu, play_folder);
10129 }
10130 if (res < 0)
10131 goto out;
10132
10133
10134 if (vms.lastmsg == -1) {
10135 in_urgent = 0;
10136 cmd = vm_browse_messages(chan, &vms, vmu);
10137 res = 0;
10138 goto out;
10139 }
10140 } else {
10141 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
10142
10143 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10144 in_urgent = 0;
10145 play_folder = 1;
10146 if (res < 0)
10147 goto out;
10148 } else if (!vms.urgentmessages && vms.newmessages) {
10149
10150 in_urgent = 0;
10151 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10152 if (res < 0)
10153 goto out;
10154 }
10155 }
10156
10157 if (useadsi)
10158 adsi_status(chan, &vms);
10159 res = 0;
10160
10161
10162 if (!strcasecmp(vmu->mailbox, vmu->password) &&
10163 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
10164 if (ast_play_and_wait(chan, "vm-newuser") == -1)
10165 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
10166 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10167 if ((cmd == 't') || (cmd == '#')) {
10168
10169 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
10170 res = 0;
10171 goto out;
10172 } else if (cmd < 0) {
10173
10174 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
10175 res = -1;
10176 goto out;
10177 }
10178 }
10179 #ifdef IMAP_STORAGE
10180 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10181 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10182 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
10183 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10184 }
10185 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10186 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
10187 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
10188 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10189 }
10190 #endif
10191
10192 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
10193 if (play_auto) {
10194 cmd = '1';
10195 } else {
10196 cmd = vm_intro(chan, vmu, &vms);
10197 }
10198 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10199
10200 vms.repeats = 0;
10201 vms.starting = 1;
10202 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10203
10204 switch (cmd) {
10205 case '1':
10206 vms.curmsg = 0;
10207
10208 case '5':
10209 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10210 cmd = vm_browse_messages(chan, &vms, vmu);
10211 break;
10212 case '2':
10213 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
10214 if (useadsi)
10215 adsi_folders(chan, 0, "Change to folder...");
10216
10217 cmd = get_folder2(chan, "vm-changeto", 0);
10218 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10219 if (cmd == '#') {
10220 cmd = 0;
10221 } else if (cmd > 0) {
10222 cmd = cmd - '0';
10223 res = close_mailbox(&vms, vmu);
10224 if (res == ERROR_LOCK_PATH)
10225 goto out;
10226
10227 if (cmd != 11) in_urgent = 0;
10228 res = open_mailbox(&vms, vmu, cmd);
10229 if (res < 0)
10230 goto out;
10231 play_folder = cmd;
10232 cmd = 0;
10233 }
10234 if (useadsi)
10235 adsi_status2(chan, &vms);
10236
10237 if (!cmd) {
10238 cmd = vm_play_folder_name(chan, vms.vmbox);
10239 }
10240
10241 vms.starting = 1;
10242 vms.curmsg = 0;
10243 break;
10244 case '3':
10245 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
10246 cmd = 0;
10247 vms.repeats = 0;
10248 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
10249 switch (cmd) {
10250 case '1':
10251 if (vms.lastmsg > -1 && !vms.starting) {
10252 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
10253 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10254 res = cmd;
10255 goto out;
10256 }
10257 } else {
10258 cmd = ast_play_and_wait(chan, "vm-sorry");
10259 }
10260 cmd = 't';
10261 break;
10262 case '2':
10263 if (!vms.starting)
10264 ast_verb(3, "Callback Requested\n");
10265 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
10266 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
10267 if (cmd == 9) {
10268 silentexit = 1;
10269 goto out;
10270 } else if (cmd == ERROR_LOCK_PATH) {
10271 res = cmd;
10272 goto out;
10273 }
10274 } else {
10275 cmd = ast_play_and_wait(chan, "vm-sorry");
10276 }
10277 cmd = 't';
10278 break;
10279 case '3':
10280 if (vms.lastmsg > -1 && !vms.starting) {
10281 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
10282 if (cmd == ERROR_LOCK_PATH) {
10283 res = cmd;
10284 goto out;
10285 }
10286 } else {
10287 cmd = ast_play_and_wait(chan, "vm-sorry");
10288 }
10289 cmd = 't';
10290 break;
10291 case '4':
10292 if (!ast_strlen_zero(vmu->dialout)) {
10293 cmd = dialout(chan, vmu, NULL, vmu->dialout);
10294 if (cmd == 9) {
10295 silentexit = 1;
10296 goto out;
10297 }
10298 } else {
10299 cmd = ast_play_and_wait(chan, "vm-sorry");
10300 }
10301 cmd = 't';
10302 break;
10303
10304 case '5':
10305 if (ast_test_flag(vmu, VM_SVMAIL)) {
10306 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10307 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
10308 res = cmd;
10309 goto out;
10310 }
10311 } else {
10312 cmd = ast_play_and_wait(chan, "vm-sorry");
10313 }
10314 cmd = 't';
10315 break;
10316
10317 case '*':
10318 cmd = 't';
10319 break;
10320
10321 default:
10322 cmd = 0;
10323 if (!vms.starting) {
10324 cmd = ast_play_and_wait(chan, "vm-toreply");
10325 }
10326 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
10327 cmd = ast_play_and_wait(chan, "vm-tocallback");
10328 }
10329 if (!cmd && !vms.starting) {
10330 cmd = ast_play_and_wait(chan, "vm-tohearenv");
10331 }
10332 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
10333 cmd = ast_play_and_wait(chan, "vm-tomakecall");
10334 }
10335 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
10336 cmd = ast_play_and_wait(chan, "vm-leavemsg");
10337 }
10338 if (!cmd) {
10339 cmd = ast_play_and_wait(chan, "vm-starmain");
10340 }
10341 if (!cmd) {
10342 cmd = ast_waitfordigit(chan, 6000);
10343 }
10344 if (!cmd) {
10345 vms.repeats++;
10346 }
10347 if (vms.repeats > 3) {
10348 cmd = 't';
10349 }
10350 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10351 }
10352 }
10353 if (cmd == 't') {
10354 cmd = 0;
10355 vms.repeats = 0;
10356 }
10357 break;
10358 case '4':
10359 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
10360 if (vms.curmsg > 0) {
10361 vms.curmsg--;
10362 cmd = play_message(chan, vmu, &vms);
10363 } else {
10364
10365
10366
10367
10368 if (in_urgent == 0 && vms.urgentmessages > 0) {
10369
10370 in_urgent = 1;
10371 res = close_mailbox(&vms, vmu);
10372 if (res == ERROR_LOCK_PATH)
10373 goto out;
10374 res = open_mailbox(&vms, vmu, 11);
10375 if (res < 0)
10376 goto out;
10377 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
10378 vms.curmsg = vms.lastmsg;
10379 if (vms.lastmsg < 0) {
10380 cmd = ast_play_and_wait(chan, "vm-nomore");
10381 }
10382 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10383 vms.curmsg = vms.lastmsg;
10384 cmd = play_message(chan, vmu, &vms);
10385 } else {
10386 cmd = ast_play_and_wait(chan, "vm-nomore");
10387 }
10388 }
10389 break;
10390 case '6':
10391 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
10392 if (vms.curmsg < vms.lastmsg) {
10393 vms.curmsg++;
10394 cmd = play_message(chan, vmu, &vms);
10395 } else {
10396 if (in_urgent && vms.newmessages > 0) {
10397
10398
10399
10400
10401 in_urgent = 0;
10402 res = close_mailbox(&vms, vmu);
10403 if (res == ERROR_LOCK_PATH)
10404 goto out;
10405 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10406 if (res < 0)
10407 goto out;
10408 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10409 vms.curmsg = -1;
10410 if (vms.lastmsg < 0) {
10411 cmd = ast_play_and_wait(chan, "vm-nomore");
10412 }
10413 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10414 vms.curmsg = 0;
10415 cmd = play_message(chan, vmu, &vms);
10416 } else {
10417 cmd = ast_play_and_wait(chan, "vm-nomore");
10418 }
10419 }
10420 break;
10421 case '7':
10422 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
10423 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
10424 if (useadsi)
10425 adsi_delete(chan, &vms);
10426 if (vms.deleted[vms.curmsg]) {
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-deleted");
10437 } else {
10438 if (play_folder == 0) {
10439 if (in_urgent) {
10440 vms.urgentmessages++;
10441 } else {
10442 vms.newmessages++;
10443 }
10444 }
10445 else if (play_folder == 1)
10446 vms.oldmessages++;
10447 cmd = ast_play_and_wait(chan, "vm-undeleted");
10448 }
10449 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10450 if (vms.curmsg < vms.lastmsg) {
10451 vms.curmsg++;
10452 cmd = play_message(chan, vmu, &vms);
10453 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10454 vms.curmsg = 0;
10455 cmd = play_message(chan, vmu, &vms);
10456 } else {
10457
10458
10459
10460
10461 if (in_urgent == 1) {
10462
10463 in_urgent = 0;
10464 res = close_mailbox(&vms, vmu);
10465 if (res == ERROR_LOCK_PATH)
10466 goto out;
10467 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10468 if (res < 0)
10469 goto out;
10470 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10471 vms.curmsg = -1;
10472 if (vms.lastmsg < 0) {
10473 cmd = ast_play_and_wait(chan, "vm-nomore");
10474 }
10475 } else {
10476 cmd = ast_play_and_wait(chan, "vm-nomore");
10477 }
10478 }
10479 }
10480 } else
10481 cmd = 0;
10482 #ifdef IMAP_STORAGE
10483 deleted = 1;
10484 #endif
10485 break;
10486
10487 case '8':
10488 if (vms.lastmsg > -1) {
10489 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10490 if (cmd == ERROR_LOCK_PATH) {
10491 res = cmd;
10492 goto out;
10493 }
10494 } else {
10495
10496
10497
10498
10499 if (in_urgent == 1 && vms.newmessages > 0) {
10500
10501 in_urgent = 0;
10502 res = close_mailbox(&vms, vmu);
10503 if (res == ERROR_LOCK_PATH)
10504 goto out;
10505 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10506 if (res < 0)
10507 goto out;
10508 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10509 vms.curmsg = -1;
10510 if (vms.lastmsg < 0) {
10511 cmd = ast_play_and_wait(chan, "vm-nomore");
10512 }
10513 } else {
10514 cmd = ast_play_and_wait(chan, "vm-nomore");
10515 }
10516 }
10517 break;
10518 case '9':
10519 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
10520 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
10521
10522 cmd = 0;
10523 break;
10524 }
10525 if (useadsi)
10526 adsi_folders(chan, 1, "Save to folder...");
10527 cmd = get_folder2(chan, "vm-savefolder", 1);
10528 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10529 box = 0;
10530 if (cmd == '#') {
10531 cmd = 0;
10532 break;
10533 } else if (cmd > 0) {
10534 box = cmd = cmd - '0';
10535 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd);
10536 if (cmd == ERROR_LOCK_PATH) {
10537 res = cmd;
10538 goto out;
10539 #ifndef IMAP_STORAGE
10540 } else if (!cmd) {
10541 vms.deleted[vms.curmsg] = 1;
10542 #endif
10543 } else {
10544 vms.deleted[vms.curmsg] = 0;
10545 vms.heard[vms.curmsg] = 0;
10546 }
10547 }
10548 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
10549 if (useadsi)
10550 adsi_message(chan, &vms);
10551 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
10552 if (!cmd) {
10553 cmd = ast_play_and_wait(chan, "vm-message");
10554 if (!cmd)
10555 cmd = say_and_wait(chan, vms.curmsg + 1, chan->language);
10556 if (!cmd)
10557 cmd = ast_play_and_wait(chan, "vm-savedto");
10558 if (!cmd)
10559 cmd = vm_play_folder_name(chan, vms.fn);
10560 } else {
10561 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
10562 }
10563 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
10564 if (vms.curmsg < vms.lastmsg) {
10565 vms.curmsg++;
10566 cmd = play_message(chan, vmu, &vms);
10567 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
10568 vms.curmsg = 0;
10569 cmd = play_message(chan, vmu, &vms);
10570 } else {
10571
10572
10573
10574
10575 if (in_urgent == 1 && vms.newmessages > 0) {
10576
10577 in_urgent = 0;
10578 res = close_mailbox(&vms, vmu);
10579 if (res == ERROR_LOCK_PATH)
10580 goto out;
10581 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10582 if (res < 0)
10583 goto out;
10584 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
10585 vms.curmsg = -1;
10586 if (vms.lastmsg < 0) {
10587 cmd = ast_play_and_wait(chan, "vm-nomore");
10588 }
10589 } else {
10590 cmd = ast_play_and_wait(chan, "vm-nomore");
10591 }
10592 }
10593 }
10594 break;
10595 case '*':
10596 if (!vms.starting) {
10597 cmd = ast_play_and_wait(chan, "vm-onefor");
10598 if (!strncasecmp(chan->language, "he", 2)) {
10599 cmd = ast_play_and_wait(chan, "vm-for");
10600 }
10601 if (!cmd)
10602 cmd = vm_play_folder_name(chan, vms.vmbox);
10603 if (!cmd)
10604 cmd = ast_play_and_wait(chan, "vm-opts");
10605 if (!cmd)
10606 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
10607 } else
10608 cmd = 0;
10609 break;
10610 case '0':
10611 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
10612 if (useadsi)
10613 adsi_status(chan, &vms);
10614 break;
10615 default:
10616 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
10617 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
10618 break;
10619 }
10620 }
10621 if ((cmd == 't') || (cmd == '#')) {
10622
10623 res = 0;
10624 } else {
10625
10626 res = -1;
10627 }
10628
10629 out:
10630 if (res > -1) {
10631 ast_stopstream(chan);
10632 adsi_goodbye(chan);
10633 if (valid && res != OPERATOR_EXIT) {
10634 if (silentexit)
10635 res = ast_play_and_wait(chan, "vm-dialout");
10636 else
10637 res = ast_play_and_wait(chan, "vm-goodbye");
10638 }
10639 if ((valid && res > 0) || res == OPERATOR_EXIT) {
10640 res = 0;
10641 }
10642 if (useadsi)
10643 ast_adsi_unload_session(chan);
10644 }
10645 if (vmu)
10646 close_mailbox(&vms, vmu);
10647 if (valid) {
10648 int new = 0, old = 0, urgent = 0;
10649 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
10650 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
10651
10652 run_externnotify(vmu->context, vmu->mailbox, NULL);
10653 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
10654 queue_mwi_event(ext_context, urgent, new, old);
10655 }
10656 #ifdef IMAP_STORAGE
10657
10658 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10659 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10660 ast_mutex_lock(&vms.lock);
10661 #ifdef HAVE_IMAP_TK2006
10662 if (LEVELUIDPLUS (vms.mailstream)) {
10663 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10664 } else
10665 #endif
10666 mail_expunge(vms.mailstream);
10667 ast_mutex_unlock(&vms.lock);
10668 }
10669
10670
10671 if (vmu) {
10672 vmstate_delete(&vms);
10673 }
10674 #endif
10675 if (vmu)
10676 free_user(vmu);
10677
10678 #ifdef IMAP_STORAGE
10679 pthread_setspecific(ts_vmstate.key, NULL);
10680 #endif
10681 return res;
10682 }
10683
10684 static int vm_exec(struct ast_channel *chan, const char *data)
10685 {
10686 int res = 0;
10687 char *tmp;
10688 struct leave_vm_options leave_options;
10689 struct ast_flags flags = { 0 };
10690 char *opts[OPT_ARG_ARRAY_SIZE];
10691 AST_DECLARE_APP_ARGS(args,
10692 AST_APP_ARG(argv0);
10693 AST_APP_ARG(argv1);
10694 );
10695
10696 memset(&leave_options, 0, sizeof(leave_options));
10697
10698 if (chan->_state != AST_STATE_UP)
10699 ast_answer(chan);
10700
10701 if (!ast_strlen_zero(data)) {
10702 tmp = ast_strdupa(data);
10703 AST_STANDARD_APP_ARGS(args, tmp);
10704 if (args.argc == 2) {
10705 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10706 return -1;
10707 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
10708 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10709 int gain;
10710
10711 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10712 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10713 return -1;
10714 } else {
10715 leave_options.record_gain = (signed char) gain;
10716 }
10717 }
10718 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
10719 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
10720 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
10721 }
10722 }
10723 } else {
10724 char temp[256];
10725 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
10726 if (res < 0)
10727 return res;
10728 if (ast_strlen_zero(temp))
10729 return 0;
10730 args.argv0 = ast_strdupa(temp);
10731 }
10732
10733 res = leave_voicemail(chan, args.argv0, &leave_options);
10734 if (res == 't') {
10735 ast_play_and_wait(chan, "vm-goodbye");
10736 res = 0;
10737 }
10738
10739 if (res == OPERATOR_EXIT) {
10740 res = 0;
10741 }
10742
10743 if (res == ERROR_LOCK_PATH) {
10744 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
10745 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
10746 res = 0;
10747 }
10748
10749 return res;
10750 }
10751
10752 static struct ast_vm_user *find_or_create(const char *context, const char *box)
10753 {
10754 struct ast_vm_user *vmu;
10755
10756 if (!ast_strlen_zero(box) && box[0] == '*') {
10757 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
10758 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10759 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10760 "\n\tand will be ignored.\n", box, context);
10761 return NULL;
10762 }
10763
10764 AST_LIST_TRAVERSE(&users, vmu, list) {
10765 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
10766 if (strcasecmp(vmu->context, context)) {
10767 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
10768 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10769 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10770 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10771 }
10772 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
10773 return NULL;
10774 }
10775 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
10776 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
10777 return NULL;
10778 }
10779 }
10780
10781 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
10782 return NULL;
10783
10784 ast_copy_string(vmu->context, context, sizeof(vmu->context));
10785 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
10786
10787 AST_LIST_INSERT_TAIL(&users, vmu, list);
10788
10789 return vmu;
10790 }
10791
10792 static int append_mailbox(const char *context, const char *box, const char *data)
10793 {
10794
10795 char *tmp;
10796 char *stringp;
10797 char *s;
10798 struct ast_vm_user *vmu;
10799 char *mailbox_full;
10800 int new = 0, old = 0, urgent = 0;
10801 char secretfn[PATH_MAX] = "";
10802
10803 tmp = ast_strdupa(data);
10804
10805 if (!(vmu = find_or_create(context, box)))
10806 return -1;
10807
10808 populate_defaults(vmu);
10809
10810 stringp = tmp;
10811 if ((s = strsep(&stringp, ","))) {
10812 if (!ast_strlen_zero(s) && s[0] == '*') {
10813 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
10814 "\n\tmust be reset in voicemail.conf.\n", box);
10815 }
10816
10817 ast_copy_string(vmu->password, s, sizeof(vmu->password));
10818 }
10819 if (stringp && (s = strsep(&stringp, ","))) {
10820 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
10821 }
10822 if (stringp && (s = strsep(&stringp, ","))) {
10823 ast_copy_string(vmu->email, s, sizeof(vmu->email));
10824 }
10825 if (stringp && (s = strsep(&stringp, ","))) {
10826 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
10827 }
10828 if (stringp && (s = strsep(&stringp, ","))) {
10829 apply_options(vmu, s);
10830 }
10831
10832 switch (vmu->passwordlocation) {
10833 case OPT_PWLOC_SPOOLDIR:
10834 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
10835 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
10836 }
10837
10838 mailbox_full = ast_alloca(strlen(box) + strlen(context) + 1);
10839 strcpy(mailbox_full, box);
10840 strcat(mailbox_full, "@");
10841 strcat(mailbox_full, context);
10842
10843 inboxcount2(mailbox_full, &urgent, &new, &old);
10844 queue_mwi_event(mailbox_full, urgent, new, old);
10845
10846 return 0;
10847 }
10848
10849 AST_TEST_DEFINE(test_voicemail_vmuser)
10850 {
10851 int res = 0;
10852 struct ast_vm_user *vmu;
10853
10854 static const char options_string[] = "attach=yes|attachfmt=wav49|"
10855 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10856 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10857 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10858 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10859 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10860 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10861 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10862 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10863 #ifdef IMAP_STORAGE
10864 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
10865 "imapfolder=INBOX|imapvmshareid=6000";
10866 #endif
10867
10868 switch (cmd) {
10869 case TEST_INIT:
10870 info->name = "vmuser";
10871 info->category = "/apps/app_voicemail/";
10872 info->summary = "Vmuser unit test";
10873 info->description =
10874 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10875 return AST_TEST_NOT_RUN;
10876 case TEST_EXECUTE:
10877 break;
10878 }
10879
10880 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
10881 return AST_TEST_NOT_RUN;
10882 }
10883 populate_defaults(vmu);
10884 ast_set_flag(vmu, VM_ALLOCED);
10885
10886 apply_options(vmu, options_string);
10887
10888 if (!ast_test_flag(vmu, VM_ATTACH)) {
10889 ast_test_status_update(test, "Parse failure for attach option\n");
10890 res = 1;
10891 }
10892 if (strcasecmp(vmu->attachfmt, "wav49")) {
10893 ast_test_status_update(test, "Parse failure for attachftm option\n");
10894 res = 1;
10895 }
10896 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
10897 ast_test_status_update(test, "Parse failure for serveremail option\n");
10898 res = 1;
10899 }
10900 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10901 ast_test_status_update(test, "Parse failure for emailsubject option\n");
10902 res = 1;
10903 }
10904 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10905 ast_test_status_update(test, "Parse failure for emailbody option\n");
10906 res = 1;
10907 }
10908 if (strcasecmp(vmu->zonetag, "central")) {
10909 ast_test_status_update(test, "Parse failure for tz option\n");
10910 res = 1;
10911 }
10912 if (!ast_test_flag(vmu, VM_DELETE)) {
10913 ast_test_status_update(test, "Parse failure for delete option\n");
10914 res = 1;
10915 }
10916 if (!ast_test_flag(vmu, VM_SAYCID)) {
10917 ast_test_status_update(test, "Parse failure for saycid option\n");
10918 res = 1;
10919 }
10920 if (!ast_test_flag(vmu, VM_SVMAIL)) {
10921 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
10922 res = 1;
10923 }
10924 if (!ast_test_flag(vmu, VM_REVIEW)) {
10925 ast_test_status_update(test, "Parse failure for review option\n");
10926 res = 1;
10927 }
10928 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
10929 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
10930 res = 1;
10931 }
10932 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
10933 ast_test_status_update(test, "Parse failure for messagewrap option\n");
10934 res = 1;
10935 }
10936 if (!ast_test_flag(vmu, VM_OPERATOR)) {
10937 ast_test_status_update(test, "Parse failure for operator option\n");
10938 res = 1;
10939 }
10940 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
10941 ast_test_status_update(test, "Parse failure for envelope option\n");
10942 res = 1;
10943 }
10944 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
10945 ast_test_status_update(test, "Parse failure for moveheard option\n");
10946 res = 1;
10947 }
10948 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
10949 ast_test_status_update(test, "Parse failure for sayduration option\n");
10950 res = 1;
10951 }
10952 if (vmu->saydurationm != 5) {
10953 ast_test_status_update(test, "Parse failure for saydurationm option\n");
10954 res = 1;
10955 }
10956 if (!ast_test_flag(vmu, VM_FORCENAME)) {
10957 ast_test_status_update(test, "Parse failure for forcename option\n");
10958 res = 1;
10959 }
10960 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
10961 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
10962 res = 1;
10963 }
10964 if (strcasecmp(vmu->callback, "somecontext")) {
10965 ast_test_status_update(test, "Parse failure for callbacks option\n");
10966 res = 1;
10967 }
10968 if (strcasecmp(vmu->dialout, "somecontext2")) {
10969 ast_test_status_update(test, "Parse failure for dialout option\n");
10970 res = 1;
10971 }
10972 if (strcasecmp(vmu->exit, "somecontext3")) {
10973 ast_test_status_update(test, "Parse failure for exitcontext option\n");
10974 res = 1;
10975 }
10976 if (vmu->minsecs != 10) {
10977 ast_test_status_update(test, "Parse failure for minsecs option\n");
10978 res = 1;
10979 }
10980 if (vmu->maxsecs != 100) {
10981 ast_test_status_update(test, "Parse failure for maxsecs option\n");
10982 res = 1;
10983 }
10984 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
10985 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
10986 res = 1;
10987 }
10988 if (vmu->maxdeletedmsg != 50) {
10989 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
10990 res = 1;
10991 }
10992 if (vmu->volgain != 1.3) {
10993 ast_test_status_update(test, "Parse failure for volgain option\n");
10994 res = 1;
10995 }
10996 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
10997 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
10998 res = 1;
10999 }
11000 #ifdef IMAP_STORAGE
11001 apply_options(vmu, option_string2);
11002
11003 if (strcasecmp(vmu->imapuser, "imapuser")) {
11004 ast_test_status_update(test, "Parse failure for imapuser option\n");
11005 res = 1;
11006 }
11007 if (strcasecmp(vmu->imappassword, "imappasswd")) {
11008 ast_test_status_update(test, "Parse failure for imappasswd option\n");
11009 res = 1;
11010 }
11011 if (strcasecmp(vmu->imapfolder, "INBOX")) {
11012 ast_test_status_update(test, "Parse failure for imapfolder option\n");
11013 res = 1;
11014 }
11015 if (strcasecmp(vmu->imapvmshareid, "6000")) {
11016 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
11017 res = 1;
11018 }
11019 #endif
11020
11021 free_user(vmu);
11022 return res ? AST_TEST_FAIL : AST_TEST_PASS;
11023 }
11024
11025 static int vm_box_exists(struct ast_channel *chan, const char *data)
11026 {
11027 struct ast_vm_user svm;
11028 char *context, *box;
11029 AST_DECLARE_APP_ARGS(args,
11030 AST_APP_ARG(mbox);
11031 AST_APP_ARG(options);
11032 );
11033 static int dep_warning = 0;
11034
11035 if (ast_strlen_zero(data)) {
11036 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
11037 return -1;
11038 }
11039
11040 if (!dep_warning) {
11041 dep_warning = 1;
11042 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (char *) data);
11043 }
11044
11045 box = ast_strdupa(data);
11046
11047 AST_STANDARD_APP_ARGS(args, box);
11048
11049 if (args.options) {
11050 }
11051
11052 if ((context = strchr(args.mbox, '@'))) {
11053 *context = '\0';
11054 context++;
11055 }
11056
11057 if (find_user(&svm, context, args.mbox)) {
11058 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
11059 } else
11060 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
11061
11062 return 0;
11063 }
11064
11065 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
11066 {
11067 struct ast_vm_user svm;
11068 AST_DECLARE_APP_ARGS(arg,
11069 AST_APP_ARG(mbox);
11070 AST_APP_ARG(context);
11071 );
11072
11073 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
11074
11075 if (ast_strlen_zero(arg.mbox)) {
11076 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11077 return -1;
11078 }
11079
11080 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
11081 return 0;
11082 }
11083
11084 static struct ast_custom_function mailbox_exists_acf = {
11085 .name = "MAILBOX_EXISTS",
11086 .read = acf_mailbox_exists,
11087 };
11088
11089 static int vmauthenticate(struct ast_channel *chan, const char *data)
11090 {
11091 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
11092 struct ast_vm_user vmus;
11093 char *options = NULL;
11094 int silent = 0, skipuser = 0;
11095 int res = -1;
11096
11097 if (data) {
11098 s = ast_strdupa(data);
11099 user = strsep(&s, ",");
11100 options = strsep(&s, ",");
11101 if (user) {
11102 s = user;
11103 user = strsep(&s, "@");
11104 context = strsep(&s, "");
11105 if (!ast_strlen_zero(user))
11106 skipuser++;
11107 ast_copy_string(mailbox, user, sizeof(mailbox));
11108 }
11109 }
11110
11111 if (options) {
11112 silent = (strchr(options, 's')) != NULL;
11113 }
11114
11115 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11116 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
11117 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
11118 ast_play_and_wait(chan, "auth-thankyou");
11119 res = 0;
11120 } else if (mailbox[0] == '*') {
11121
11122 if (!ast_goto_if_exists(chan, chan->context, "a", 1)) {
11123 res = 0;
11124 }
11125 }
11126
11127 return res;
11128 }
11129
11130 static char *show_users_realtime(int fd, const char *context)
11131 {
11132 struct ast_config *cfg;
11133 const char *cat = NULL;
11134
11135 if (!(cfg = ast_load_realtime_multientry("voicemail",
11136 "context", context, SENTINEL))) {
11137 return CLI_FAILURE;
11138 }
11139
11140 ast_cli(fd,
11141 "\n"
11142 "=============================================================\n"
11143 "=== Configured Voicemail Users ==============================\n"
11144 "=============================================================\n"
11145 "===\n");
11146
11147 while ((cat = ast_category_browse(cfg, cat))) {
11148 struct ast_variable *var = NULL;
11149 ast_cli(fd,
11150 "=== Mailbox ...\n"
11151 "===\n");
11152 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
11153 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
11154 ast_cli(fd,
11155 "===\n"
11156 "=== ---------------------------------------------------------\n"
11157 "===\n");
11158 }
11159
11160 ast_cli(fd,
11161 "=============================================================\n"
11162 "\n");
11163
11164 ast_config_destroy(cfg);
11165
11166 return CLI_SUCCESS;
11167 }
11168
11169 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
11170 {
11171 int which = 0;
11172 int wordlen;
11173 struct ast_vm_user *vmu;
11174 const char *context = "";
11175
11176
11177 if (pos > 4)
11178 return NULL;
11179 if (pos == 3)
11180 return (state == 0) ? ast_strdup("for") : NULL;
11181 wordlen = strlen(word);
11182 AST_LIST_TRAVERSE(&users, vmu, list) {
11183 if (!strncasecmp(word, vmu->context, wordlen)) {
11184 if (context && strcmp(context, vmu->context) && ++which > state)
11185 return ast_strdup(vmu->context);
11186
11187 context = vmu->context;
11188 }
11189 }
11190 return NULL;
11191 }
11192
11193
11194 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11195 {
11196 struct ast_vm_user *vmu;
11197 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11198 const char *context = NULL;
11199 int users_counter = 0;
11200
11201 switch (cmd) {
11202 case CLI_INIT:
11203 e->command = "voicemail show users";
11204 e->usage =
11205 "Usage: voicemail show users [for <context>]\n"
11206 " Lists all mailboxes currently set up\n";
11207 return NULL;
11208 case CLI_GENERATE:
11209 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
11210 }
11211
11212 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
11213 return CLI_SHOWUSAGE;
11214 if (a->argc == 5) {
11215 if (strcmp(a->argv[3],"for"))
11216 return CLI_SHOWUSAGE;
11217 context = a->argv[4];
11218 }
11219
11220 if (ast_check_realtime("voicemail")) {
11221 if (!context) {
11222 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
11223 return CLI_SHOWUSAGE;
11224 }
11225 return show_users_realtime(a->fd, context);
11226 }
11227
11228 AST_LIST_LOCK(&users);
11229 if (AST_LIST_EMPTY(&users)) {
11230 ast_cli(a->fd, "There are no voicemail users currently defined\n");
11231 AST_LIST_UNLOCK(&users);
11232 return CLI_FAILURE;
11233 }
11234 if (!context) {
11235 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11236 } else {
11237 int count = 0;
11238 AST_LIST_TRAVERSE(&users, vmu, list) {
11239 if (!strcmp(context, vmu->context)) {
11240 count++;
11241 break;
11242 }
11243 }
11244 if (count) {
11245 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
11246 } else {
11247 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
11248 AST_LIST_UNLOCK(&users);
11249 return CLI_FAILURE;
11250 }
11251 }
11252 AST_LIST_TRAVERSE(&users, vmu, list) {
11253 int newmsgs = 0, oldmsgs = 0;
11254 char count[12], tmp[256] = "";
11255
11256 if (!context || !strcmp(context, vmu->context)) {
11257 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
11258 inboxcount(tmp, &newmsgs, &oldmsgs);
11259 snprintf(count, sizeof(count), "%d", newmsgs);
11260 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
11261 users_counter++;
11262 }
11263 }
11264 AST_LIST_UNLOCK(&users);
11265 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
11266 return CLI_SUCCESS;
11267 }
11268
11269
11270 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11271 {
11272 struct vm_zone *zone;
11273 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11274 char *res = CLI_SUCCESS;
11275
11276 switch (cmd) {
11277 case CLI_INIT:
11278 e->command = "voicemail show zones";
11279 e->usage =
11280 "Usage: voicemail show zones\n"
11281 " Lists zone message formats\n";
11282 return NULL;
11283 case CLI_GENERATE:
11284 return NULL;
11285 }
11286
11287 if (a->argc != 3)
11288 return CLI_SHOWUSAGE;
11289
11290 AST_LIST_LOCK(&zones);
11291 if (!AST_LIST_EMPTY(&zones)) {
11292 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
11293 AST_LIST_TRAVERSE(&zones, zone, list) {
11294 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
11295 }
11296 } else {
11297 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
11298 res = CLI_FAILURE;
11299 }
11300 AST_LIST_UNLOCK(&zones);
11301
11302 return res;
11303 }
11304
11305
11306 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11307 {
11308 switch (cmd) {
11309 case CLI_INIT:
11310 e->command = "voicemail reload";
11311 e->usage =
11312 "Usage: voicemail reload\n"
11313 " Reload voicemail configuration\n";
11314 return NULL;
11315 case CLI_GENERATE:
11316 return NULL;
11317 }
11318
11319 if (a->argc != 2)
11320 return CLI_SHOWUSAGE;
11321
11322 ast_cli(a->fd, "Reloading voicemail configuration...\n");
11323 load_config(1);
11324
11325 return CLI_SUCCESS;
11326 }
11327
11328 static struct ast_cli_entry cli_voicemail[] = {
11329 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
11330 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
11331 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
11332 };
11333
11334 #ifdef IMAP_STORAGE
11335 #define DATA_EXPORT_VM_USERS(USER) \
11336 USER(ast_vm_user, context, AST_DATA_STRING) \
11337 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11338 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11339 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11340 USER(ast_vm_user, email, AST_DATA_STRING) \
11341 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11342 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11343 USER(ast_vm_user, pager, AST_DATA_STRING) \
11344 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11345 USER(ast_vm_user, language, AST_DATA_STRING) \
11346 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11347 USER(ast_vm_user, callback, AST_DATA_STRING) \
11348 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11349 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11350 USER(ast_vm_user, exit, AST_DATA_STRING) \
11351 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11352 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11353 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11354 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11355 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11356 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11357 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11358 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11359 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11360 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11361 #else
11362 #define DATA_EXPORT_VM_USERS(USER) \
11363 USER(ast_vm_user, context, AST_DATA_STRING) \
11364 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11365 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11366 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11367 USER(ast_vm_user, email, AST_DATA_STRING) \
11368 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11369 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11370 USER(ast_vm_user, pager, AST_DATA_STRING) \
11371 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11372 USER(ast_vm_user, language, AST_DATA_STRING) \
11373 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11374 USER(ast_vm_user, callback, AST_DATA_STRING) \
11375 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11376 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11377 USER(ast_vm_user, exit, AST_DATA_STRING) \
11378 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11379 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11380 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11381 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11382 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11383 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11384 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11385 #endif
11386
11387 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
11388
11389 #define DATA_EXPORT_VM_ZONES(ZONE) \
11390 ZONE(vm_zone, name, AST_DATA_STRING) \
11391 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11392 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11393
11394 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
11395
11396
11397
11398
11399
11400
11401
11402
11403 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
11404 struct ast_data *data_root, struct ast_vm_user *user)
11405 {
11406 struct ast_data *data_user, *data_zone;
11407 struct ast_data *data_state;
11408 struct vm_zone *zone = NULL;
11409 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11410 char ext_context[256] = "";
11411
11412 data_user = ast_data_add_node(data_root, "user");
11413 if (!data_user) {
11414 return -1;
11415 }
11416
11417 ast_data_add_structure(ast_vm_user, data_user, user);
11418
11419 AST_LIST_LOCK(&zones);
11420 AST_LIST_TRAVERSE(&zones, zone, list) {
11421 if (!strcmp(zone->name, user->zonetag)) {
11422 break;
11423 }
11424 }
11425 AST_LIST_UNLOCK(&zones);
11426
11427
11428 data_state = ast_data_add_node(data_user, "state");
11429 if (!data_state) {
11430 return -1;
11431 }
11432 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
11433 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11434 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
11435 ast_data_add_int(data_state, "newmsg", newmsg);
11436 ast_data_add_int(data_state, "oldmsg", oldmsg);
11437
11438 if (zone) {
11439 data_zone = ast_data_add_node(data_user, "zone");
11440 ast_data_add_structure(vm_zone, data_zone, zone);
11441 }
11442
11443 if (!ast_data_search_match(search, data_user)) {
11444 ast_data_remove_node(data_root, data_user);
11445 }
11446
11447 return 0;
11448 }
11449
11450 static int vm_users_data_provider_get(const struct ast_data_search *search,
11451 struct ast_data *data_root)
11452 {
11453 struct ast_vm_user *user;
11454
11455 AST_LIST_LOCK(&users);
11456 AST_LIST_TRAVERSE(&users, user, list) {
11457 vm_users_data_provider_get_helper(search, data_root, user);
11458 }
11459 AST_LIST_UNLOCK(&users);
11460
11461 return 0;
11462 }
11463
11464 static const struct ast_data_handler vm_users_data_provider = {
11465 .version = AST_DATA_HANDLER_VERSION,
11466 .get = vm_users_data_provider_get
11467 };
11468
11469 static const struct ast_data_entry vm_data_providers[] = {
11470 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
11471 };
11472
11473 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
11474 {
11475 int new = 0, old = 0, urgent = 0;
11476
11477 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
11478
11479 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
11480 mwi_sub->old_urgent = urgent;
11481 mwi_sub->old_new = new;
11482 mwi_sub->old_old = old;
11483 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
11484 run_externnotify(NULL, mwi_sub->mailbox, NULL);
11485 }
11486 }
11487
11488 static void poll_subscribed_mailboxes(void)
11489 {
11490 struct mwi_sub *mwi_sub;
11491
11492 AST_RWLIST_RDLOCK(&mwi_subs);
11493 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
11494 if (!ast_strlen_zero(mwi_sub->mailbox)) {
11495 poll_subscribed_mailbox(mwi_sub);
11496 }
11497 }
11498 AST_RWLIST_UNLOCK(&mwi_subs);
11499 }
11500
11501 static void *mb_poll_thread(void *data)
11502 {
11503 while (poll_thread_run) {
11504 struct timespec ts = { 0, };
11505 struct timeval wait;
11506
11507 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
11508 ts.tv_sec = wait.tv_sec;
11509 ts.tv_nsec = wait.tv_usec * 1000;
11510
11511 ast_mutex_lock(&poll_lock);
11512 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
11513 ast_mutex_unlock(&poll_lock);
11514
11515 if (!poll_thread_run)
11516 break;
11517
11518 poll_subscribed_mailboxes();
11519 }
11520
11521 return NULL;
11522 }
11523
11524 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
11525 {
11526 ast_free(mwi_sub);
11527 }
11528
11529 static int handle_unsubscribe(void *datap)
11530 {
11531 struct mwi_sub *mwi_sub;
11532 uint32_t *uniqueid = datap;
11533
11534 AST_RWLIST_WRLOCK(&mwi_subs);
11535 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
11536 if (mwi_sub->uniqueid == *uniqueid) {
11537 AST_LIST_REMOVE_CURRENT(entry);
11538 break;
11539 }
11540 }
11541 AST_RWLIST_TRAVERSE_SAFE_END
11542 AST_RWLIST_UNLOCK(&mwi_subs);
11543
11544 if (mwi_sub)
11545 mwi_sub_destroy(mwi_sub);
11546
11547 ast_free(uniqueid);
11548 return 0;
11549 }
11550
11551 static int handle_subscribe(void *datap)
11552 {
11553 unsigned int len;
11554 struct mwi_sub *mwi_sub;
11555 struct mwi_sub_task *p = datap;
11556
11557 len = sizeof(*mwi_sub);
11558 if (!ast_strlen_zero(p->mailbox))
11559 len += strlen(p->mailbox);
11560
11561 if (!ast_strlen_zero(p->context))
11562 len += strlen(p->context) + 1;
11563
11564 if (!(mwi_sub = ast_calloc(1, len)))
11565 return -1;
11566
11567 mwi_sub->uniqueid = p->uniqueid;
11568 if (!ast_strlen_zero(p->mailbox))
11569 strcpy(mwi_sub->mailbox, p->mailbox);
11570
11571 if (!ast_strlen_zero(p->context)) {
11572 strcat(mwi_sub->mailbox, "@");
11573 strcat(mwi_sub->mailbox, p->context);
11574 }
11575
11576 AST_RWLIST_WRLOCK(&mwi_subs);
11577 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
11578 AST_RWLIST_UNLOCK(&mwi_subs);
11579 ast_free((void *) p->mailbox);
11580 ast_free((void *) p->context);
11581 ast_free(p);
11582 poll_subscribed_mailbox(mwi_sub);
11583 return 0;
11584 }
11585
11586 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
11587 {
11588 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
11589
11590 if (!uniqueid) {
11591 ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n");
11592 return;
11593 }
11594
11595 if (ast_event_get_type(event) != AST_EVENT_UNSUB) {
11596 ast_free(uniqueid);
11597 return;
11598 }
11599
11600 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI) {
11601 ast_free(uniqueid);
11602 return;
11603 }
11604
11605 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11606 *uniqueid = u;
11607 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
11608 ast_free(uniqueid);
11609 }
11610 }
11611
11612 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
11613 {
11614 struct mwi_sub_task *mwist;
11615
11616 if (ast_event_get_type(event) != AST_EVENT_SUB)
11617 return;
11618
11619 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
11620 return;
11621
11622 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
11623 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
11624 return;
11625 }
11626 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
11627 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
11628 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
11629
11630 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
11631 ast_free(mwist);
11632 }
11633 }
11634
11635 static void start_poll_thread(void)
11636 {
11637 int errcode;
11638 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
11639 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11640 AST_EVENT_IE_END);
11641
11642 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
11643 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
11644 AST_EVENT_IE_END);
11645
11646 if (mwi_sub_sub)
11647 ast_event_report_subs(mwi_sub_sub);
11648
11649 poll_thread_run = 1;
11650
11651 if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL))) {
11652 ast_log(LOG_ERROR, "Could not create thread: %s\n", strerror(errcode));
11653 }
11654 }
11655
11656 static void stop_poll_thread(void)
11657 {
11658 poll_thread_run = 0;
11659
11660 if (mwi_sub_sub) {
11661 ast_event_unsubscribe(mwi_sub_sub);
11662 mwi_sub_sub = NULL;
11663 }
11664
11665 if (mwi_unsub_sub) {
11666 ast_event_unsubscribe(mwi_unsub_sub);
11667 mwi_unsub_sub = NULL;
11668 }
11669
11670 ast_mutex_lock(&poll_lock);
11671 ast_cond_signal(&poll_cond);
11672 ast_mutex_unlock(&poll_lock);
11673
11674 pthread_join(poll_thread, NULL);
11675
11676 poll_thread = AST_PTHREADT_NULL;
11677 }
11678
11679
11680 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
11681 {
11682 struct ast_vm_user *vmu = NULL;
11683 const char *id = astman_get_header(m, "ActionID");
11684 char actionid[128] = "";
11685
11686 if (!ast_strlen_zero(id))
11687 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
11688
11689 AST_LIST_LOCK(&users);
11690
11691 if (AST_LIST_EMPTY(&users)) {
11692 astman_send_ack(s, m, "There are no voicemail users currently defined.");
11693 AST_LIST_UNLOCK(&users);
11694 return RESULT_SUCCESS;
11695 }
11696
11697 astman_send_ack(s, m, "Voicemail user list will follow");
11698
11699 AST_LIST_TRAVERSE(&users, vmu, list) {
11700 char dirname[256];
11701
11702 #ifdef IMAP_STORAGE
11703 int new, old;
11704 inboxcount(vmu->mailbox, &new, &old);
11705 #endif
11706
11707 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
11708 astman_append(s,
11709 "%s"
11710 "Event: VoicemailUserEntry\r\n"
11711 "VMContext: %s\r\n"
11712 "VoiceMailbox: %s\r\n"
11713 "Fullname: %s\r\n"
11714 "Email: %s\r\n"
11715 "Pager: %s\r\n"
11716 "ServerEmail: %s\r\n"
11717 "MailCommand: %s\r\n"
11718 "Language: %s\r\n"
11719 "TimeZone: %s\r\n"
11720 "Callback: %s\r\n"
11721 "Dialout: %s\r\n"
11722 "UniqueID: %s\r\n"
11723 "ExitContext: %s\r\n"
11724 "SayDurationMinimum: %d\r\n"
11725 "SayEnvelope: %s\r\n"
11726 "SayCID: %s\r\n"
11727 "AttachMessage: %s\r\n"
11728 "AttachmentFormat: %s\r\n"
11729 "DeleteMessage: %s\r\n"
11730 "VolumeGain: %.2f\r\n"
11731 "CanReview: %s\r\n"
11732 "CallOperator: %s\r\n"
11733 "MaxMessageCount: %d\r\n"
11734 "MaxMessageLength: %d\r\n"
11735 "NewMessageCount: %d\r\n"
11736 #ifdef IMAP_STORAGE
11737 "OldMessageCount: %d\r\n"
11738 "IMAPUser: %s\r\n"
11739 #endif
11740 "\r\n",
11741 actionid,
11742 vmu->context,
11743 vmu->mailbox,
11744 vmu->fullname,
11745 vmu->email,
11746 vmu->pager,
11747 ast_strlen_zero(vmu->serveremail) ? serveremail : vmu->serveremail,
11748 mailcmd,
11749 vmu->language,
11750 vmu->zonetag,
11751 vmu->callback,
11752 vmu->dialout,
11753 vmu->uniqueid,
11754 vmu->exit,
11755 vmu->saydurationm,
11756 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
11757 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
11758 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
11759 vmu->attachfmt,
11760 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
11761 vmu->volgain,
11762 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
11763 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
11764 vmu->maxmsg,
11765 vmu->maxsecs,
11766 #ifdef IMAP_STORAGE
11767 new, old, vmu->imapuser
11768 #else
11769 count_messages(vmu, dirname)
11770 #endif
11771 );
11772 }
11773 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11774
11775 AST_LIST_UNLOCK(&users);
11776
11777 return RESULT_SUCCESS;
11778 }
11779
11780
11781 static void free_vm_users(void)
11782 {
11783 struct ast_vm_user *current;
11784 AST_LIST_LOCK(&users);
11785 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
11786 ast_set_flag(current, VM_ALLOCED);
11787 free_user(current);
11788 }
11789 AST_LIST_UNLOCK(&users);
11790 }
11791
11792
11793 static void free_vm_zones(void)
11794 {
11795 struct vm_zone *zcur;
11796 AST_LIST_LOCK(&zones);
11797 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
11798 free_zone(zcur);
11799 AST_LIST_UNLOCK(&zones);
11800 }
11801
11802 static const char *substitute_escapes(const char *value)
11803 {
11804 char *current;
11805
11806
11807 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
11808
11809 ast_str_reset(str);
11810
11811
11812 for (current = (char *) value; *current; current++) {
11813 if (*current == '\\') {
11814 current++;
11815 if (!*current) {
11816 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
11817 break;
11818 }
11819 switch (*current) {
11820 case '\\':
11821 ast_str_append(&str, 0, "\\");
11822 break;
11823 case 'r':
11824 ast_str_append(&str, 0, "\r");
11825 break;
11826 case 'n':
11827 #ifdef IMAP_STORAGE
11828 if (!str->used || str->str[str->used - 1] != '\r') {
11829 ast_str_append(&str, 0, "\r");
11830 }
11831 #endif
11832 ast_str_append(&str, 0, "\n");
11833 break;
11834 case 't':
11835 ast_str_append(&str, 0, "\t");
11836 break;
11837 default:
11838 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
11839 break;
11840 }
11841 } else {
11842 ast_str_append(&str, 0, "%c", *current);
11843 }
11844 }
11845
11846 return ast_str_buffer(str);
11847 }
11848
11849 static int load_config(int reload)
11850 {
11851 struct ast_config *cfg, *ucfg;
11852 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
11853 int res;
11854
11855 ast_unload_realtime("voicemail");
11856 ast_unload_realtime("voicemail_data");
11857
11858 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11859 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
11860 return 0;
11861 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
11862 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11863 ucfg = NULL;
11864 }
11865 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11866 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
11867 ast_config_destroy(ucfg);
11868 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11869 return 0;
11870 }
11871 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
11872 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
11873 return 0;
11874 } else {
11875 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
11876 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
11877 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
11878 ucfg = NULL;
11879 }
11880 }
11881
11882 res = actual_load_config(reload, cfg, ucfg);
11883
11884 ast_config_destroy(cfg);
11885 ast_config_destroy(ucfg);
11886
11887 return res;
11888 }
11889
11890 #ifdef TEST_FRAMEWORK
11891 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11892 {
11893 ast_unload_realtime("voicemail");
11894 ast_unload_realtime("voicemail_data");
11895 return actual_load_config(reload, cfg, ucfg);
11896 }
11897 #endif
11898
11899 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
11900 {
11901 struct ast_vm_user *current;
11902 char *cat;
11903 struct ast_variable *var;
11904 const char *val;
11905 char *q, *stringp, *tmp;
11906 int x;
11907 unsigned int tmpadsi[4];
11908 char secretfn[PATH_MAX] = "";
11909
11910 #ifdef IMAP_STORAGE
11911 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
11912 #endif
11913
11914 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
11915 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
11916 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
11917 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
11918 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
11919
11920
11921 free_vm_users();
11922
11923
11924 free_vm_zones();
11925
11926 AST_LIST_LOCK(&users);
11927
11928 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
11929 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
11930
11931 if (cfg) {
11932
11933
11934 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
11935 val = "default";
11936 ast_copy_string(userscontext, val, sizeof(userscontext));
11937
11938 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
11939 val = "yes";
11940 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
11941
11942 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
11943 val = "no";
11944 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
11945
11946 volgain = 0.0;
11947 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
11948 sscanf(val, "%30lf", &volgain);
11949
11950 #ifdef ODBC_STORAGE
11951 strcpy(odbc_database, "asterisk");
11952 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
11953 ast_copy_string(odbc_database, val, sizeof(odbc_database));
11954 }
11955 strcpy(odbc_table, "voicemessages");
11956 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
11957 ast_copy_string(odbc_table, val, sizeof(odbc_table));
11958 }
11959 #endif
11960
11961 strcpy(mailcmd, SENDMAIL);
11962 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
11963 ast_copy_string(mailcmd, val, sizeof(mailcmd));
11964
11965 maxsilence = 0;
11966 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
11967 maxsilence = atoi(val);
11968 if (maxsilence > 0)
11969 maxsilence *= 1000;
11970 }
11971
11972 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
11973 maxmsg = MAXMSG;
11974 } else {
11975 maxmsg = atoi(val);
11976 if (maxmsg < 0) {
11977 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
11978 maxmsg = MAXMSG;
11979 } else if (maxmsg > MAXMSGLIMIT) {
11980 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
11981 maxmsg = MAXMSGLIMIT;
11982 }
11983 }
11984
11985 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
11986 maxdeletedmsg = 0;
11987 } else {
11988 if (sscanf(val, "%30d", &x) == 1)
11989 maxdeletedmsg = x;
11990 else if (ast_true(val))
11991 maxdeletedmsg = MAXMSG;
11992 else
11993 maxdeletedmsg = 0;
11994
11995 if (maxdeletedmsg < 0) {
11996 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
11997 maxdeletedmsg = MAXMSG;
11998 } else if (maxdeletedmsg > MAXMSGLIMIT) {
11999 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
12000 maxdeletedmsg = MAXMSGLIMIT;
12001 }
12002 }
12003
12004
12005 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
12006 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
12007 }
12008
12009
12010 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
12011 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
12012 }
12013
12014
12015 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
12016 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
12017 pwdchange = PWDCHANGE_EXTERNAL;
12018 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
12019 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
12020 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
12021 }
12022
12023
12024 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
12025 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
12026 ast_log(AST_LOG_DEBUG, "found externpasscheck: %s\n", ext_pass_check_cmd);
12027 }
12028
12029 #ifdef IMAP_STORAGE
12030
12031 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
12032 ast_copy_string(imapserver, val, sizeof(imapserver));
12033 } else {
12034 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
12035 }
12036
12037 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
12038 ast_copy_string(imapport, val, sizeof(imapport));
12039 } else {
12040 ast_copy_string(imapport, "143", sizeof(imapport));
12041 }
12042
12043 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
12044 ast_copy_string(imapflags, val, sizeof(imapflags));
12045 }
12046
12047 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
12048 ast_copy_string(authuser, val, sizeof(authuser));
12049 }
12050
12051 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
12052 ast_copy_string(authpassword, val, sizeof(authpassword));
12053 }
12054
12055 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
12056 if (ast_false(val))
12057 expungeonhangup = 0;
12058 else
12059 expungeonhangup = 1;
12060 } else {
12061 expungeonhangup = 1;
12062 }
12063
12064 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
12065 ast_copy_string(imapfolder, val, sizeof(imapfolder));
12066 } else {
12067 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
12068 }
12069 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
12070 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
12071 }
12072 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
12073 imapgreetings = ast_true(val);
12074 } else {
12075 imapgreetings = 0;
12076 }
12077 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
12078 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12079 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
12080
12081 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
12082 } else {
12083 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
12084 }
12085
12086
12087
12088
12089
12090 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
12091 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
12092 } else {
12093 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
12094 }
12095
12096 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
12097 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
12098 } else {
12099 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
12100 }
12101
12102 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
12103 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
12104 } else {
12105 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
12106 }
12107
12108 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
12109 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
12110 } else {
12111 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
12112 }
12113
12114
12115 imapversion++;
12116 #endif
12117
12118 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
12119 ast_copy_string(externnotify, val, sizeof(externnotify));
12120 ast_debug(1, "found externnotify: %s\n", externnotify);
12121 } else {
12122 externnotify[0] = '\0';
12123 }
12124
12125
12126 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
12127 ast_debug(1, "Enabled SMDI voicemail notification\n");
12128 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
12129 smdi_iface = ast_smdi_interface_find(val);
12130 } else {
12131 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
12132 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
12133 }
12134 if (!smdi_iface) {
12135 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12136 }
12137 }
12138
12139
12140 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
12141 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
12142 silencethreshold = atoi(val);
12143
12144 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
12145 val = ASTERISK_USERNAME;
12146 ast_copy_string(serveremail, val, sizeof(serveremail));
12147
12148 vmmaxsecs = 0;
12149 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
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 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
12156 static int maxmessage_deprecate = 0;
12157 if (maxmessage_deprecate == 0) {
12158 maxmessage_deprecate = 1;
12159 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
12160 }
12161 if (sscanf(val, "%30d", &x) == 1) {
12162 vmmaxsecs = x;
12163 } else {
12164 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
12165 }
12166 }
12167
12168 vmminsecs = 0;
12169 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
12170 if (sscanf(val, "%30d", &x) == 1) {
12171 vmminsecs = x;
12172 if (maxsilence / 1000 >= vmminsecs) {
12173 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
12174 }
12175 } else {
12176 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12177 }
12178 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
12179 static int maxmessage_deprecate = 0;
12180 if (maxmessage_deprecate == 0) {
12181 maxmessage_deprecate = 1;
12182 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
12183 }
12184 if (sscanf(val, "%30d", &x) == 1) {
12185 vmminsecs = x;
12186 if (maxsilence / 1000 >= vmminsecs) {
12187 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
12188 }
12189 } else {
12190 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
12191 }
12192 }
12193
12194 val = ast_variable_retrieve(cfg, "general", "format");
12195 if (!val) {
12196 val = "wav";
12197 } else {
12198 tmp = ast_strdupa(val);
12199 val = ast_format_str_reduce(tmp);
12200 if (!val) {
12201 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
12202 val = "wav";
12203 }
12204 }
12205 ast_copy_string(vmfmts, val, sizeof(vmfmts));
12206
12207 skipms = 3000;
12208 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
12209 if (sscanf(val, "%30d", &x) == 1) {
12210 maxgreet = x;
12211 } else {
12212 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
12213 }
12214 }
12215
12216 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
12217 if (sscanf(val, "%30d", &x) == 1) {
12218 skipms = x;
12219 } else {
12220 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
12221 }
12222 }
12223
12224 maxlogins = 3;
12225 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
12226 if (sscanf(val, "%30d", &x) == 1) {
12227 maxlogins = x;
12228 } else {
12229 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
12230 }
12231 }
12232
12233 minpassword = MINPASSWORD;
12234 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
12235 if (sscanf(val, "%30d", &x) == 1) {
12236 minpassword = x;
12237 } else {
12238 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
12239 }
12240 }
12241
12242
12243 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
12244 val = "no";
12245 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
12246
12247
12248 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
12249 val = "no";
12250 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
12251
12252 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
12253 ast_debug(1, "VM_CID Internal context string: %s\n", val);
12254 stringp = ast_strdupa(val);
12255 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
12256 if (!ast_strlen_zero(stringp)) {
12257 q = strsep(&stringp, ",");
12258 while ((*q == ' ')||(*q == '\t'))
12259 q++;
12260 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
12261 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12262 } else {
12263 cidinternalcontexts[x][0] = '\0';
12264 }
12265 }
12266 }
12267 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
12268 ast_debug(1, "VM Review Option disabled globally\n");
12269 val = "no";
12270 }
12271 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
12272
12273
12274 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
12275 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
12276 val = "no";
12277 } else {
12278 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
12279 }
12280 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
12281 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
12282 ast_debug(1, "VM next message wrap disabled globally\n");
12283 val = "no";
12284 }
12285 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
12286
12287 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
12288 ast_debug(1, "VM Operator break disabled globally\n");
12289 val = "no";
12290 }
12291 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
12292
12293 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
12294 ast_debug(1, "VM CID Info before msg disabled globally\n");
12295 val = "no";
12296 }
12297 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
12298
12299 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
12300 ast_debug(1, "Send Voicemail msg disabled globally\n");
12301 val = "no";
12302 }
12303 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
12304
12305 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
12306 ast_debug(1, "ENVELOPE before msg enabled globally\n");
12307 val = "yes";
12308 }
12309 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
12310
12311 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
12312 ast_debug(1, "Move Heard enabled globally\n");
12313 val = "yes";
12314 }
12315 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
12316
12317 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
12318 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12319 val = "no";
12320 }
12321 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
12322
12323 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
12324 ast_debug(1, "Duration info before msg enabled globally\n");
12325 val = "yes";
12326 }
12327 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
12328
12329 saydurationminfo = 2;
12330 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
12331 if (sscanf(val, "%30d", &x) == 1) {
12332 saydurationminfo = x;
12333 } else {
12334 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
12335 }
12336 }
12337
12338 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
12339 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
12340 val = "no";
12341 }
12342 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
12343
12344 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
12345 ast_copy_string(dialcontext, val, sizeof(dialcontext));
12346 ast_debug(1, "found dialout context: %s\n", dialcontext);
12347 } else {
12348 dialcontext[0] = '\0';
12349 }
12350
12351 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
12352 ast_copy_string(callcontext, val, sizeof(callcontext));
12353 ast_debug(1, "found callback context: %s\n", callcontext);
12354 } else {
12355 callcontext[0] = '\0';
12356 }
12357
12358 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
12359 ast_copy_string(exitcontext, val, sizeof(exitcontext));
12360 ast_debug(1, "found operator context: %s\n", exitcontext);
12361 } else {
12362 exitcontext[0] = '\0';
12363 }
12364
12365
12366 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
12367 ast_copy_string(vm_password, val, sizeof(vm_password));
12368 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
12369 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
12370 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
12371 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
12372 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
12373 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
12374 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
12375 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
12376 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
12377 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
12378 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
12379 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
12380 }
12381 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
12382 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
12383 }
12384
12385 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
12386 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
12387 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
12388 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
12389 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
12390 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
12391 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
12392 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
12393 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
12394 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
12395
12396 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
12397 val = "no";
12398 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
12399
12400 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
12401 val = "voicemail.conf";
12402 }
12403 if (!(strcmp(val, "spooldir"))) {
12404 passwordlocation = OPT_PWLOC_SPOOLDIR;
12405 } else {
12406 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
12407 }
12408
12409 poll_freq = DEFAULT_POLL_FREQ;
12410 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
12411 if (sscanf(val, "%30u", &poll_freq) != 1) {
12412 poll_freq = DEFAULT_POLL_FREQ;
12413 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
12414 }
12415 }
12416
12417 poll_mailboxes = 0;
12418 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
12419 poll_mailboxes = ast_true(val);
12420
12421 memset(fromstring, 0, sizeof(fromstring));
12422 memset(pagerfromstring, 0, sizeof(pagerfromstring));
12423 strcpy(charset, "ISO-8859-1");
12424 if (emailbody) {
12425 ast_free(emailbody);
12426 emailbody = NULL;
12427 }
12428 if (emailsubject) {
12429 ast_free(emailsubject);
12430 emailsubject = NULL;
12431 }
12432 if (pagerbody) {
12433 ast_free(pagerbody);
12434 pagerbody = NULL;
12435 }
12436 if (pagersubject) {
12437 ast_free(pagersubject);
12438 pagersubject = NULL;
12439 }
12440 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
12441 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
12442 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
12443 ast_copy_string(fromstring, val, sizeof(fromstring));
12444 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
12445 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
12446 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
12447 ast_copy_string(charset, val, sizeof(charset));
12448 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
12449 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12450 for (x = 0; x < 4; x++) {
12451 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12452 }
12453 }
12454 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
12455 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12456 for (x = 0; x < 4; x++) {
12457 memcpy(&adsisec[x], &tmpadsi[x], 1);
12458 }
12459 }
12460 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
12461 if (atoi(val)) {
12462 adsiver = atoi(val);
12463 }
12464 }
12465 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
12466 ast_copy_string(zonetag, val, sizeof(zonetag));
12467 }
12468 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
12469 ast_copy_string(locale, val, sizeof(locale));
12470 }
12471 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
12472 emailsubject = ast_strdup(substitute_escapes(val));
12473 }
12474 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
12475 emailbody = ast_strdup(substitute_escapes(val));
12476 }
12477 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
12478 pagersubject = ast_strdup(substitute_escapes(val));
12479 }
12480 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
12481 pagerbody = ast_strdup(substitute_escapes(val));
12482 }
12483
12484
12485 if (ucfg) {
12486 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
12487 if (!strcasecmp(cat, "general")) {
12488 continue;
12489 }
12490 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
12491 continue;
12492 if ((current = find_or_create(userscontext, cat))) {
12493 populate_defaults(current);
12494 apply_options_full(current, ast_variable_browse(ucfg, cat));
12495 ast_copy_string(current->context, userscontext, sizeof(current->context));
12496 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
12497 current->passwordlocation = OPT_PWLOC_USERSCONF;
12498 }
12499
12500 switch (current->passwordlocation) {
12501 case OPT_PWLOC_SPOOLDIR:
12502 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
12503 read_password_from_file(secretfn, current->password, sizeof(current->password));
12504 }
12505 }
12506 }
12507 }
12508
12509
12510 cat = ast_category_browse(cfg, NULL);
12511 while (cat) {
12512 if (strcasecmp(cat, "general")) {
12513 var = ast_variable_browse(cfg, cat);
12514 if (strcasecmp(cat, "zonemessages")) {
12515
12516 while (var) {
12517 append_mailbox(cat, var->name, var->value);
12518 var = var->next;
12519 }
12520 } else {
12521
12522 while (var) {
12523 struct vm_zone *z;
12524 if ((z = ast_malloc(sizeof(*z)))) {
12525 char *msg_format, *tzone;
12526 msg_format = ast_strdupa(var->value);
12527 tzone = strsep(&msg_format, "|,");
12528 if (msg_format) {
12529 ast_copy_string(z->name, var->name, sizeof(z->name));
12530 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
12531 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
12532 AST_LIST_LOCK(&zones);
12533 AST_LIST_INSERT_HEAD(&zones, z, list);
12534 AST_LIST_UNLOCK(&zones);
12535 } else {
12536 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
12537 ast_free(z);
12538 }
12539 } else {
12540 AST_LIST_UNLOCK(&users);
12541 return -1;
12542 }
12543 var = var->next;
12544 }
12545 }
12546 }
12547 cat = ast_category_browse(cfg, cat);
12548 }
12549
12550 AST_LIST_UNLOCK(&users);
12551
12552 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
12553 start_poll_thread();
12554 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
12555 stop_poll_thread();;
12556
12557 return 0;
12558 } else {
12559 AST_LIST_UNLOCK(&users);
12560 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
12561 return 0;
12562 }
12563 }
12564
12565 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
12566 {
12567 int res = -1;
12568 char dir[PATH_MAX];
12569 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12570 ast_debug(2, "About to try retrieving name file %s\n", dir);
12571 RETRIEVE(dir, -1, mailbox, context);
12572 if (ast_fileexists(dir, NULL, NULL)) {
12573 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
12574 }
12575 DISPOSE(dir, -1);
12576 return res;
12577 }
12578
12579 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
12580 struct ast_config *pwconf;
12581 struct ast_flags config_flags = { 0 };
12582
12583 pwconf = ast_config_load(secretfn, config_flags);
12584 if (valid_config(pwconf)) {
12585 const char *val = ast_variable_retrieve(pwconf, "general", "password");
12586 if (val) {
12587 ast_copy_string(password, val, passwordlen);
12588 ast_config_destroy(pwconf);
12589 return;
12590 }
12591 ast_config_destroy(pwconf);
12592 }
12593 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12594 }
12595
12596 static int write_password_to_file(const char *secretfn, const char *password) {
12597 struct ast_config *conf;
12598 struct ast_category *cat;
12599 struct ast_variable *var;
12600 int res = -1;
12601
12602 if (!(conf = ast_config_new())) {
12603 ast_log(LOG_ERROR, "Error creating new config structure\n");
12604 return res;
12605 }
12606 if (!(cat = ast_category_new("general", "", 1))) {
12607 ast_log(LOG_ERROR, "Error creating new category structure\n");
12608 ast_config_destroy(conf);
12609 return res;
12610 }
12611 if (!(var = ast_variable_new("password", password, ""))) {
12612 ast_log(LOG_ERROR, "Error creating new variable structure\n");
12613 ast_config_destroy(conf);
12614 ast_category_destroy(cat);
12615 return res;
12616 }
12617 ast_category_append(conf, cat);
12618 ast_variable_append(cat, var);
12619 if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
12620 res = 0;
12621 } else {
12622 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
12623 }
12624
12625 ast_config_destroy(conf);
12626 return res;
12627 }
12628
12629 static int vmsayname_exec(struct ast_channel *chan, const char *data)
12630 {
12631 char *context;
12632 char *args_copy;
12633 int res;
12634
12635 if (ast_strlen_zero(data)) {
12636 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context\n");
12637 return -1;
12638 }
12639
12640 args_copy = ast_strdupa(data);
12641 if ((context = strchr(args_copy, '@'))) {
12642 *context++ = '\0';
12643 } else {
12644 context = "default";
12645 }
12646
12647 if ((res = sayname(chan, args_copy, context) < 0)) {
12648 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12649 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
12650 if (!res) {
12651 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, chan->language);
12652 }
12653 }
12654
12655 return res;
12656 }
12657
12658 #ifdef TEST_FRAMEWORK
12659 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
12660 {
12661 return 0;
12662 }
12663
12664 static struct ast_frame *fake_read(struct ast_channel *ast)
12665 {
12666 return &ast_null_frame;
12667 }
12668
12669 AST_TEST_DEFINE(test_voicemail_vmsayname)
12670 {
12671 char dir[PATH_MAX];
12672 char dir2[PATH_MAX];
12673 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12674 static const char TEST_EXTENSION[] = "1234";
12675
12676 struct ast_channel *test_channel1 = NULL;
12677 int res = -1;
12678
12679 static const struct ast_channel_tech fake_tech = {
12680 .write = fake_write,
12681 .read = fake_read,
12682 };
12683
12684 switch (cmd) {
12685 case TEST_INIT:
12686 info->name = "vmsayname_exec";
12687 info->category = "/apps/app_voicemail/";
12688 info->summary = "Vmsayname unit test";
12689 info->description =
12690 "This tests passing various parameters to vmsayname";
12691 return AST_TEST_NOT_RUN;
12692 case TEST_EXECUTE:
12693 break;
12694 }
12695
12696 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
12697 NULL, NULL, 0, 0, "TestChannel1"))) {
12698 goto exit_vmsayname_test;
12699 }
12700
12701
12702 test_channel1->nativeformats = AST_FORMAT_GSM;
12703 test_channel1->writeformat = AST_FORMAT_GSM;
12704 test_channel1->rawwriteformat = AST_FORMAT_GSM;
12705 test_channel1->readformat = AST_FORMAT_GSM;
12706 test_channel1->rawreadformat = AST_FORMAT_GSM;
12707 test_channel1->tech = &fake_tech;
12708
12709 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
12710 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12711 if (!(res = vmsayname_exec(test_channel1, dir))) {
12712 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12713 if (ast_fileexists(dir, NULL, NULL)) {
12714 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
12715 res = -1;
12716 goto exit_vmsayname_test;
12717 } else {
12718
12719 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
12720 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
12721 goto exit_vmsayname_test;
12722 }
12723 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
12724 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12725
12726 if ((res = symlink(dir, dir2))) {
12727 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
12728 goto exit_vmsayname_test;
12729 }
12730 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
12731 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12732 res = vmsayname_exec(test_channel1, dir);
12733
12734
12735 unlink(dir2);
12736 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12737 rmdir(dir2);
12738 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12739 rmdir(dir2);
12740 }
12741 }
12742
12743 exit_vmsayname_test:
12744
12745 if (test_channel1) {
12746 ast_hangup(test_channel1);
12747 }
12748
12749 return res ? AST_TEST_FAIL : AST_TEST_PASS;
12750 }
12751
12752 AST_TEST_DEFINE(test_voicemail_msgcount)
12753 {
12754 int i, j, res = AST_TEST_PASS, syserr;
12755 struct ast_vm_user *vmu;
12756 struct ast_vm_user svm;
12757 struct vm_state vms;
12758 #ifdef IMAP_STORAGE
12759 struct ast_channel *chan = NULL;
12760 #endif
12761 struct {
12762 char dir[256];
12763 char file[256];
12764 char txtfile[256];
12765 } tmp[3];
12766 char syscmd[256];
12767 const char origweasels[] = "tt-weasels";
12768 const char testcontext[] = "test";
12769 const char testmailbox[] = "00000000";
12770 const char testspec[] = "00000000@test";
12771 FILE *txt;
12772 int new, old, urgent;
12773 const char *folders[3] = { "Old", "Urgent", "INBOX" };
12774 const int folder2mbox[3] = { 1, 11, 0 };
12775 const int expected_results[3][12] = {
12776
12777 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12778 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12779 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12780 };
12781
12782 switch (cmd) {
12783 case TEST_INIT:
12784 info->name = "test_voicemail_msgcount";
12785 info->category = "/apps/app_voicemail/";
12786 info->summary = "Test Voicemail status checks";
12787 info->description =
12788 "Verify that message counts are correct when retrieved through the public API";
12789 return AST_TEST_NOT_RUN;
12790 case TEST_EXECUTE:
12791 break;
12792 }
12793
12794
12795 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12796 if ((syserr = ast_safe_system(syscmd))) {
12797 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12798 syserr > 0 ? strerror(syserr) : "unable to fork()");
12799 return AST_TEST_FAIL;
12800 }
12801
12802 #ifdef IMAP_STORAGE
12803 if (!(chan = ast_dummy_channel_alloc())) {
12804 ast_test_status_update(test, "Unable to create dummy channel\n");
12805 return AST_TEST_FAIL;
12806 }
12807 #endif
12808
12809 if (!(vmu = find_user(&svm, testcontext, testmailbox)) &&
12810 !(vmu = find_or_create(testcontext, testmailbox))) {
12811 ast_test_status_update(test, "Cannot create vmu structure\n");
12812 ast_unreplace_sigchld();
12813 #ifdef IMAP_STORAGE
12814 chan = ast_channel_unref(chan);
12815 #endif
12816 return AST_TEST_FAIL;
12817 }
12818
12819 populate_defaults(vmu);
12820 memset(&vms, 0, sizeof(vms));
12821
12822
12823 for (i = 0; i < 3; i++) {
12824 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12825 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
12826 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
12827
12828 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
12829 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
12830 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12831 if ((syserr = ast_safe_system(syscmd))) {
12832 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
12833 syserr > 0 ? strerror(syserr) : "unable to fork()");
12834 ast_unreplace_sigchld();
12835 #ifdef IMAP_STORAGE
12836 chan = ast_channel_unref(chan);
12837 #endif
12838 return AST_TEST_FAIL;
12839 }
12840 }
12841
12842 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
12843 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
12844 fclose(txt);
12845 } else {
12846 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
12847 res = AST_TEST_FAIL;
12848 break;
12849 }
12850 open_mailbox(&vms, vmu, folder2mbox[i]);
12851 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent");
12852
12853
12854 for (j = 0; j < 3; j++) {
12855
12856 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
12857 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
12858 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
12859 res = AST_TEST_FAIL;
12860 }
12861 }
12862
12863 new = old = urgent = 0;
12864 if (ast_app_inboxcount(testspec, &new, &old)) {
12865 ast_test_status_update(test, "inboxcount returned failure\n");
12866 res = AST_TEST_FAIL;
12867 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
12868 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
12869 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
12870 res = AST_TEST_FAIL;
12871 }
12872
12873 new = old = urgent = 0;
12874 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
12875 ast_test_status_update(test, "inboxcount2 returned failure\n");
12876 res = AST_TEST_FAIL;
12877 } else if (old != expected_results[i][6 + 0] ||
12878 urgent != expected_results[i][6 + 1] ||
12879 new != expected_results[i][6 + 2] ) {
12880 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12881 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
12882 res = AST_TEST_FAIL;
12883 }
12884
12885 new = old = urgent = 0;
12886 for (j = 0; j < 3; j++) {
12887 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12888 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
12889 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12890 res = AST_TEST_FAIL;
12891 }
12892 }
12893 }
12894
12895 for (i = 0; i < 3; i++) {
12896
12897
12898
12899 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12900 DISPOSE(tmp[i].dir, 0);
12901 }
12902
12903 if (vms.deleted) {
12904 ast_free(vms.deleted);
12905 }
12906 if (vms.heard) {
12907 ast_free(vms.heard);
12908 }
12909
12910 #ifdef IMAP_STORAGE
12911 chan = ast_channel_unref(chan);
12912 #endif
12913
12914
12915 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12916 if ((syserr = ast_safe_system(syscmd))) {
12917 ast_test_status_update(test, "Unable to clear test directory: %s\n",
12918 syserr > 0 ? strerror(syserr) : "unable to fork()");
12919 }
12920
12921 return res;
12922 }
12923
12924 AST_TEST_DEFINE(test_voicemail_notify_endl)
12925 {
12926 int res = AST_TEST_PASS;
12927 char testcontext[] = "test";
12928 char testmailbox[] = "00000000";
12929 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
12930 char attach[256], attach2[256];
12931 char buf[256] = "";
12932 struct ast_channel *chan = NULL;
12933 struct ast_vm_user *vmu, vmus = {
12934 .flags = 0,
12935 };
12936 FILE *file;
12937 struct {
12938 char *name;
12939 enum { INT, FLAGVAL, STATIC, STRPTR } type;
12940 void *location;
12941 union {
12942 int intval;
12943 char *strval;
12944 } u;
12945 } test_items[] = {
12946 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
12947 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
12948 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
12949 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12950 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
12951 { "attach2", STRPTR, attach2, .u.strval = "" },
12952 { "attach", STRPTR, attach, .u.strval = "" },
12953 };
12954 int which;
12955
12956 switch (cmd) {
12957 case TEST_INIT:
12958 info->name = "test_voicemail_notify_endl";
12959 info->category = "/apps/app_voicemail/";
12960 info->summary = "Test Voicemail notification end-of-line";
12961 info->description =
12962 "Verify that notification emails use a consistent end-of-line character";
12963 return AST_TEST_NOT_RUN;
12964 case TEST_EXECUTE:
12965 break;
12966 }
12967
12968 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
12969 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
12970
12971 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
12972 !(vmu = find_or_create(testcontext, testmailbox))) {
12973 ast_test_status_update(test, "Cannot create vmu structure\n");
12974 return AST_TEST_NOT_RUN;
12975 }
12976
12977 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
12978 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
12979 return AST_TEST_NOT_RUN;
12980 }
12981
12982 populate_defaults(vmu);
12983 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
12984 #ifdef IMAP_STORAGE
12985
12986 #endif
12987
12988 file = tmpfile();
12989 for (which = 0; which < ARRAY_LEN(test_items); which++) {
12990
12991 rewind(file);
12992 if (ftruncate(fileno(file), 0)) {
12993 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
12994 res = AST_TEST_FAIL;
12995 break;
12996 }
12997
12998
12999 if (test_items[which].type == INT) {
13000 *((int *) test_items[which].location) = test_items[which].u.intval;
13001 } else if (test_items[which].type == FLAGVAL) {
13002 if (ast_test_flag(vmu, test_items[which].u.intval)) {
13003 ast_clear_flag(vmu, test_items[which].u.intval);
13004 } else {
13005 ast_set_flag(vmu, test_items[which].u.intval);
13006 }
13007 } else if (test_items[which].type == STATIC) {
13008 strcpy(test_items[which].location, test_items[which].u.strval);
13009 } else if (test_items[which].type == STRPTR) {
13010 test_items[which].location = test_items[which].u.strval;
13011 }
13012
13013 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
13014 rewind(file);
13015 while (fgets(buf, sizeof(buf), file)) {
13016 if (
13017 #ifdef IMAP_STORAGE
13018 buf[strlen(buf) - 2] != '\r'
13019 #else
13020 buf[strlen(buf) - 2] == '\r'
13021 #endif
13022 || buf[strlen(buf) - 1] != '\n') {
13023 res = AST_TEST_FAIL;
13024 }
13025 }
13026 }
13027 fclose(file);
13028 return res;
13029 }
13030
13031 AST_TEST_DEFINE(test_voicemail_load_config)
13032 {
13033 int res = AST_TEST_PASS;
13034 struct ast_vm_user *vmu;
13035 struct ast_config *cfg;
13036 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
13037 int fd;
13038 FILE *file;
13039 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
13040
13041 switch (cmd) {
13042 case TEST_INIT:
13043 info->name = "test_voicemail_load_config";
13044 info->category = "/apps/app_voicemail/";
13045 info->summary = "Test loading Voicemail config";
13046 info->description =
13047 "Verify that configuration is loaded consistently. "
13048 "This is to test regressions of ASTERISK-18838 where it was noticed that "
13049 "some options were loaded after the mailboxes were instantiated, causing "
13050 "those options not to be set correctly.";
13051 return AST_TEST_NOT_RUN;
13052 case TEST_EXECUTE:
13053 break;
13054 }
13055
13056
13057 if ((fd = mkstemp(config_filename)) < 0) {
13058 return AST_TEST_FAIL;
13059 }
13060 if (!(file = fdopen(fd, "w"))) {
13061 close(fd);
13062 unlink(config_filename);
13063 return AST_TEST_FAIL;
13064 }
13065 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
13066 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
13067 fputs("00000002 => 9999,Mrs. Test\n", file);
13068 fclose(file);
13069
13070 if (!(cfg = ast_config_load(config_filename, config_flags)) || !valid_config(cfg)) {
13071 res = AST_TEST_FAIL;
13072 goto cleanup;
13073 }
13074
13075 load_config_from_memory(1, cfg, NULL);
13076 ast_config_destroy(cfg);
13077
13078 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
13079 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
13080 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
13081
13082 AST_LIST_LOCK(&users);
13083 AST_LIST_TRAVERSE(&users, vmu, list) {
13084 if (!strcmp(vmu->mailbox, "00000001")) {
13085 if (0);
13086 CHECK(vmu, callback, "othercontext")
13087 CHECK(vmu, locale, "nl_NL.UTF-8")
13088 CHECK(vmu, zonetag, "central")
13089 } else if (!strcmp(vmu->mailbox, "00000002")) {
13090 if (0);
13091 CHECK(vmu, callback, "somecontext")
13092 CHECK(vmu, locale, "de_DE.UTF-8")
13093 CHECK(vmu, zonetag, "european")
13094 }
13095 }
13096 AST_LIST_UNLOCK(&users);
13097
13098 #undef CHECK
13099
13100
13101 load_config(1);
13102
13103 cleanup:
13104 unlink(config_filename);
13105 return res;
13106 }
13107
13108 #endif
13109
13110 static int reload(void)
13111 {
13112 return load_config(1);
13113 }
13114
13115 static int unload_module(void)
13116 {
13117 int res;
13118
13119 res = ast_unregister_application(app);
13120 res |= ast_unregister_application(app2);
13121 res |= ast_unregister_application(app3);
13122 res |= ast_unregister_application(app4);
13123 res |= ast_unregister_application(sayname_app);
13124 res |= ast_custom_function_unregister(&mailbox_exists_acf);
13125 res |= ast_manager_unregister("VoicemailUsersList");
13126 res |= ast_data_unregister(NULL);
13127 #ifdef TEST_FRAMEWORK
13128 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
13129 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
13130 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
13131 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
13132 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
13133 #endif
13134 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13135 ast_uninstall_vm_functions();
13136 ao2_ref(inprocess_container, -1);
13137
13138 if (poll_thread != AST_PTHREADT_NULL)
13139 stop_poll_thread();
13140
13141 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
13142 ast_unload_realtime("voicemail");
13143 ast_unload_realtime("voicemail_data");
13144
13145 free_vm_users();
13146 free_vm_zones();
13147 return res;
13148 }
13149
13150 static int load_module(void)
13151 {
13152 int res;
13153 my_umask = umask(0);
13154 umask(my_umask);
13155
13156 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
13157 return AST_MODULE_LOAD_DECLINE;
13158 }
13159
13160
13161 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
13162
13163 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
13164 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
13165 }
13166
13167 if ((res = load_config(0)))
13168 return res;
13169
13170 res = ast_register_application_xml(app, vm_exec);
13171 res |= ast_register_application_xml(app2, vm_execmain);
13172 res |= ast_register_application_xml(app3, vm_box_exists);
13173 res |= ast_register_application_xml(app4, vmauthenticate);
13174 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
13175 res |= ast_custom_function_register(&mailbox_exists_acf);
13176 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
13177 #ifdef TEST_FRAMEWORK
13178 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
13179 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
13180 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
13181 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
13182 res |= AST_TEST_REGISTER(test_voicemail_load_config);
13183 #endif
13184
13185 if (res)
13186 return res;
13187
13188 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
13189 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
13190
13191 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname);
13192 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
13193 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
13194
13195 return res;
13196 }
13197
13198 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
13199 {
13200 int cmd = 0;
13201 char destination[80] = "";
13202 int retries = 0;
13203
13204 if (!num) {
13205 ast_verb(3, "Destination number will be entered manually\n");
13206 while (retries < 3 && cmd != 't') {
13207 destination[1] = '\0';
13208 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
13209 if (!cmd)
13210 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
13211 if (!cmd)
13212 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
13213 if (!cmd) {
13214 cmd = ast_waitfordigit(chan, 6000);
13215 if (cmd)
13216 destination[0] = cmd;
13217 }
13218 if (!cmd) {
13219 retries++;
13220 } else {
13221
13222 if (cmd < 0)
13223 return 0;
13224 if (cmd == '*') {
13225 ast_verb(3, "User hit '*' to cancel outgoing call\n");
13226 return 0;
13227 }
13228 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
13229 retries++;
13230 else
13231 cmd = 't';
13232 }
13233 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
13234 }
13235 if (retries >= 3) {
13236 return 0;
13237 }
13238
13239 } else {
13240 if (option_verbose > 2)
13241 ast_verbose( VERBOSE_PREFIX_3 "Destination number is CID number '%s'\n", num);
13242 ast_copy_string(destination, num, sizeof(destination));
13243 }
13244
13245 if (!ast_strlen_zero(destination)) {
13246 if (destination[strlen(destination) -1 ] == '*')
13247 return 0;
13248 if (option_verbose > 2)
13249 ast_verbose( VERBOSE_PREFIX_3 "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, chan->context);
13250 ast_copy_string(chan->exten, destination, sizeof(chan->exten));
13251 ast_copy_string(chan->context, outgoing_context, sizeof(chan->context));
13252 chan->priority = 0;
13253 return 9;
13254 }
13255 return 0;
13256 }
13257
13258
13259
13260
13261
13262
13263
13264
13265
13266
13267
13268
13269
13270
13271 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)
13272 {
13273 int res = 0;
13274 char filename[PATH_MAX];
13275 struct ast_config *msg_cfg = NULL;
13276 const char *origtime, *context;
13277 char *name, *num;
13278 int retries = 0;
13279 char *cid;
13280 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
13281
13282 vms->starting = 0;
13283
13284 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13285
13286
13287 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
13288 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
13289 msg_cfg = ast_config_load(filename, config_flags);
13290 DISPOSE(vms->curdir, vms->curmsg);
13291 if (!valid_config(msg_cfg)) {
13292 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
13293 return 0;
13294 }
13295
13296 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
13297 ast_config_destroy(msg_cfg);
13298 return 0;
13299 }
13300
13301 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
13302
13303 context = ast_variable_retrieve(msg_cfg, "message", "context");
13304 if (!strncasecmp("macro", context, 5))
13305 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
13306 switch (option) {
13307 case 3:
13308 if (!res)
13309 res = play_message_datetime(chan, vmu, origtime, filename);
13310 if (!res)
13311 res = play_message_callerid(chan, vms, cid, context, 0);
13312
13313 res = 't';
13314 break;
13315
13316 case 2:
13317
13318 if (ast_strlen_zero(cid))
13319 break;
13320
13321 ast_callerid_parse(cid, &name, &num);
13322 while ((res > -1) && (res != 't')) {
13323 switch (res) {
13324 case '1':
13325 if (num) {
13326
13327 res = dialout(chan, vmu, num, vmu->callback);
13328 if (res) {
13329 ast_config_destroy(msg_cfg);
13330 return 9;
13331 }
13332 } else {
13333 res = '2';
13334 }
13335 break;
13336
13337 case '2':
13338
13339 if (!ast_strlen_zero(vmu->dialout)) {
13340 res = dialout(chan, vmu, NULL, vmu->dialout);
13341 if (res) {
13342 ast_config_destroy(msg_cfg);
13343 return 9;
13344 }
13345 } else {
13346 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
13347 res = ast_play_and_wait(chan, "vm-sorry");
13348 }
13349 ast_config_destroy(msg_cfg);
13350 return res;
13351 case '*':
13352 res = 't';
13353 break;
13354 case '3':
13355 case '4':
13356 case '5':
13357 case '6':
13358 case '7':
13359 case '8':
13360 case '9':
13361 case '0':
13362
13363 res = ast_play_and_wait(chan, "vm-sorry");
13364 retries++;
13365 break;
13366 default:
13367 if (num) {
13368 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
13369 res = ast_play_and_wait(chan, "vm-num-i-have");
13370 if (!res)
13371 res = play_message_callerid(chan, vms, num, vmu->context, 1);
13372 if (!res)
13373 res = ast_play_and_wait(chan, "vm-tocallnum");
13374
13375 if (!ast_strlen_zero(vmu->dialout)) {
13376 if (!res)
13377 res = ast_play_and_wait(chan, "vm-calldiffnum");
13378 }
13379 } else {
13380 res = ast_play_and_wait(chan, "vm-nonumber");
13381 if (!ast_strlen_zero(vmu->dialout)) {
13382 if (!res)
13383 res = ast_play_and_wait(chan, "vm-toenternumber");
13384 }
13385 }
13386 if (!res) {
13387 res = ast_play_and_wait(chan, "vm-star-cancel");
13388 }
13389 if (!res) {
13390 res = ast_waitfordigit(chan, 6000);
13391 }
13392 if (!res) {
13393 retries++;
13394 if (retries > 3) {
13395 res = 't';
13396 }
13397 }
13398 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
13399 break;
13400
13401 }
13402 if (res == 't')
13403 res = 0;
13404 else if (res == '*')
13405 res = -1;
13406 }
13407 break;
13408
13409 case 1:
13410
13411 if (ast_strlen_zero(cid))
13412 break;
13413
13414 ast_callerid_parse(cid, &name, &num);
13415 if (!num) {
13416 ast_verb(3, "No CID number available, no reply sent\n");
13417 if (!res)
13418 res = ast_play_and_wait(chan, "vm-nonumber");
13419 ast_config_destroy(msg_cfg);
13420 return res;
13421 } else {
13422 struct ast_vm_user vmu2;
13423 if (find_user(&vmu2, vmu->context, num)) {
13424 struct leave_vm_options leave_options;
13425 char mailbox[AST_MAX_EXTENSION * 2 + 2];
13426 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
13427
13428 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
13429
13430 memset(&leave_options, 0, sizeof(leave_options));
13431 leave_options.record_gain = record_gain;
13432 res = leave_voicemail(chan, mailbox, &leave_options);
13433 if (!res)
13434 res = 't';
13435 ast_config_destroy(msg_cfg);
13436 return res;
13437 } else {
13438
13439 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
13440 ast_play_and_wait(chan, "vm-nobox");
13441 res = 't';
13442 ast_config_destroy(msg_cfg);
13443 return res;
13444 }
13445 }
13446 res = 0;
13447
13448 break;
13449 }
13450
13451 ast_config_destroy(msg_cfg);
13452
13453 #ifndef IMAP_STORAGE
13454 if (!res) {
13455 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
13456 vms->heard[msg] = 1;
13457 res = wait_file(chan, vms, vms->fn);
13458 }
13459 #endif
13460 return res;
13461 }
13462
13463 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
13464 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
13465 signed char record_gain, struct vm_state *vms, char *flag)
13466 {
13467
13468 int res = 0;
13469 int cmd = 0;
13470 int max_attempts = 3;
13471 int attempts = 0;
13472 int recorded = 0;
13473 int msg_exists = 0;
13474 signed char zero_gain = 0;
13475 char tempfile[PATH_MAX];
13476 char *acceptdtmf = "#";
13477 char *canceldtmf = "";
13478 int canceleddtmf = 0;
13479
13480
13481
13482
13483 if (duration == NULL) {
13484 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
13485 return -1;
13486 }
13487
13488 if (!outsidecaller)
13489 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
13490 else
13491 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
13492
13493 cmd = '3';
13494
13495 while ((cmd >= 0) && (cmd != 't')) {
13496 switch (cmd) {
13497 case '1':
13498 if (!msg_exists) {
13499
13500 cmd = '3';
13501 break;
13502 } else {
13503
13504 ast_verb(3, "Saving message as is\n");
13505 if (!outsidecaller)
13506 ast_filerename(tempfile, recordfile, NULL);
13507 ast_stream_and_wait(chan, "vm-msgsaved", "");
13508 if (!outsidecaller) {
13509
13510 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag);
13511 DISPOSE(recordfile, -1);
13512 }
13513 cmd = 't';
13514 return res;
13515 }
13516 case '2':
13517
13518 ast_verb(3, "Reviewing the message\n");
13519 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
13520 break;
13521 case '3':
13522 msg_exists = 0;
13523
13524 if (recorded == 1)
13525 ast_verb(3, "Re-recording the message\n");
13526 else
13527 ast_verb(3, "Recording the message\n");
13528
13529 if (recorded && outsidecaller) {
13530 cmd = ast_play_and_wait(chan, INTRO);
13531 cmd = ast_play_and_wait(chan, "beep");
13532 }
13533 recorded = 1;
13534
13535 if (record_gain)
13536 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
13537 if (ast_test_flag(vmu, VM_OPERATOR))
13538 canceldtmf = "0";
13539 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13540 if (strchr(canceldtmf, cmd)) {
13541
13542 canceleddtmf = 1;
13543 }
13544 if (record_gain)
13545 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
13546 if (cmd == -1) {
13547
13548 if (!outsidecaller) {
13549
13550 ast_filedelete(tempfile, NULL);
13551 }
13552 return cmd;
13553 }
13554 if (cmd == '0') {
13555 break;
13556 } else if (cmd == '*') {
13557 break;
13558 #if 0
13559 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13560
13561 ast_verb(3, "Message too short\n");
13562 cmd = ast_play_and_wait(chan, "vm-tooshort");
13563 cmd = ast_filedelete(tempfile, NULL);
13564 break;
13565 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13566
13567 ast_verb(3, "Nothing recorded\n");
13568 cmd = ast_filedelete(tempfile, NULL);
13569 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
13570 if (!cmd)
13571 cmd = ast_play_and_wait(chan, "vm-speakup");
13572 break;
13573 #endif
13574 } else {
13575
13576 msg_exists = 1;
13577 cmd = 0;
13578 }
13579 break;
13580 case '4':
13581 if (outsidecaller) {
13582
13583 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13584 ast_verbose(VERBOSE_PREFIX_3 "marking message as Urgent\n");
13585 res = ast_play_and_wait(chan, "vm-marked-urgent");
13586 strcpy(flag, "Urgent");
13587 } else if (flag) {
13588 ast_verbose(VERBOSE_PREFIX_3 "UNmarking message as Urgent\n");
13589 res = ast_play_and_wait(chan, "vm-marked-nonurgent");
13590 strcpy(flag, "");
13591 } else {
13592 ast_play_and_wait(chan, "vm-sorry");
13593 }
13594 cmd = 0;
13595 } else {
13596 cmd = ast_play_and_wait(chan, "vm-sorry");
13597 }
13598 break;
13599 case '5':
13600 case '6':
13601 case '7':
13602 case '8':
13603 case '9':
13604 case '*':
13605 case '#':
13606 cmd = ast_play_and_wait(chan, "vm-sorry");
13607 break;
13608 #if 0
13609
13610
13611 case '*':
13612
13613 cmd = ast_play_and_wait(chan, "vm-deleted");
13614 cmd = ast_filedelete(tempfile, NULL);
13615 if (outsidecaller) {
13616 res = vm_exec(chan, NULL);
13617 return res;
13618 }
13619 else
13620 return 1;
13621 #endif
13622 case '0':
13623 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
13624 cmd = ast_play_and_wait(chan, "vm-sorry");
13625 break;
13626 }
13627 if (msg_exists || recorded) {
13628 cmd = ast_play_and_wait(chan, "vm-saveoper");
13629 if (!cmd)
13630 cmd = ast_waitfordigit(chan, 3000);
13631 if (cmd == '1') {
13632 ast_filerename(tempfile, recordfile, NULL);
13633 ast_play_and_wait(chan, "vm-msgsaved");
13634 cmd = '0';
13635 } else if (cmd == '4') {
13636 if (flag) {
13637 ast_play_and_wait(chan, "vm-marked-urgent");
13638 strcpy(flag, "Urgent");
13639 }
13640 ast_play_and_wait(chan, "vm-msgsaved");
13641 cmd = '0';
13642 } else {
13643 ast_play_and_wait(chan, "vm-deleted");
13644 DELETE(tempfile, -1, tempfile, vmu);
13645 cmd = '0';
13646 }
13647 }
13648 return cmd;
13649 default:
13650
13651
13652
13653 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
13654 return cmd;
13655 if (msg_exists) {
13656 cmd = ast_play_and_wait(chan, "vm-review");
13657 if (!cmd && outsidecaller) {
13658 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
13659 cmd = ast_play_and_wait(chan, "vm-review-urgent");
13660 } else if (flag) {
13661 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
13662 }
13663 }
13664 } else {
13665 cmd = ast_play_and_wait(chan, "vm-torerecord");
13666 if (!cmd)
13667 cmd = ast_waitfordigit(chan, 600);
13668 }
13669
13670 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
13671 cmd = ast_play_and_wait(chan, "vm-reachoper");
13672 if (!cmd)
13673 cmd = ast_waitfordigit(chan, 600);
13674 }
13675 #if 0
13676 if (!cmd)
13677 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
13678 #endif
13679 if (!cmd)
13680 cmd = ast_waitfordigit(chan, 6000);
13681 if (!cmd) {
13682 attempts++;
13683 }
13684 if (attempts > max_attempts) {
13685 cmd = 't';
13686 }
13687 }
13688 }
13689 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
13690
13691 ast_filedelete(tempfile, NULL);
13692 }
13693
13694 if (cmd != 't' && outsidecaller)
13695 ast_play_and_wait(chan, "vm-goodbye");
13696
13697 return cmd;
13698 }
13699
13700
13701
13702
13703
13704 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
13705 .load = load_module,
13706 .unload = unload_module,
13707 .reload = reload,
13708 .nonoptreq = "res_adsi,res_smdi",
13709 );