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: 412324 $")
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/strings.h"
00123 #include "asterisk/smdi.h"
00124 #include "asterisk/astobj2.h"
00125 #include "asterisk/event.h"
00126 #include "asterisk/taskprocessor.h"
00127 #include "asterisk/test.h"
00128
00129 #ifdef ODBC_STORAGE
00130 #include "asterisk/res_odbc.h"
00131 #endif
00132
00133 #ifdef IMAP_STORAGE
00134 #include "asterisk/threadstorage.h"
00135 #endif
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
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460 #ifdef IMAP_STORAGE
00461 static char imapserver[48];
00462 static char imapport[8];
00463 static char imapflags[128];
00464 static char imapfolder[64];
00465 static char imapparentfolder[64] = "\0";
00466 static char greetingfolder[64];
00467 static char authuser[32];
00468 static char authpassword[42];
00469 static int imapversion = 1;
00470
00471 static int expungeonhangup = 1;
00472 static int imapgreetings = 0;
00473 static char delimiter = '\0';
00474
00475 struct vm_state;
00476 struct ast_vm_user;
00477
00478 AST_THREADSTORAGE(ts_vmstate);
00479
00480
00481 static int init_mailstream(struct vm_state *vms, int box);
00482 static void write_file(char *filename, char *buffer, unsigned long len);
00483 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len);
00484 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu);
00485 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len);
00486 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive);
00487 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive);
00488 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu);
00489 static void vmstate_insert(struct vm_state *vms);
00490 static void vmstate_delete(struct vm_state *vms);
00491 static void set_update(MAILSTREAM * stream);
00492 static void init_vm_state(struct vm_state *vms);
00493 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
00494 static void get_mailbox_delimiter(struct vm_state *vms, MAILSTREAM *stream);
00495 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
00496 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
00497 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, const char *msg_id);
00498 static void vm_imap_update_msg_id(char *dir, int msgnum, const char *msg_id, struct ast_vm_user *vmu, struct ast_config *msg_cfg, int folder);
00499 static void update_messages_by_imapuser(const char *user, unsigned long number);
00500 static int vm_delete(char *file);
00501
00502 static int imap_remove_file (char *dir, int msgnum);
00503 static int imap_retrieve_file (const char *dir, const int msgnum, const char *mailbox, const char *context);
00504 static int imap_delete_old_greeting (char *dir, struct vm_state *vms);
00505 static void check_quota(struct vm_state *vms, char *mailbox);
00506 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
00507 struct vmstate {
00508 struct vm_state *vms;
00509 AST_LIST_ENTRY(vmstate) list;
00510 };
00511
00512 static AST_LIST_HEAD_STATIC(vmstates, vmstate);
00513
00514 #endif
00515
00516 #define SMDI_MWI_WAIT_TIMEOUT 1000
00517
00518 #define COMMAND_TIMEOUT 5000
00519
00520 #define VOICEMAIL_DIR_MODE 0777
00521 #define VOICEMAIL_FILE_MODE 0666
00522 #define CHUNKSIZE 65536
00523
00524 #define VOICEMAIL_CONFIG "voicemail.conf"
00525 #define ASTERISK_USERNAME "asterisk"
00526
00527
00528
00529
00530 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
00531 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
00532 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
00533 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
00534 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
00535 #define VALID_DTMF "1234567890*#"
00536
00537
00538
00539 #define SENDMAIL "/usr/sbin/sendmail -t"
00540
00541 #define INTRO "vm-intro"
00542
00543 #define MAXMSG 100
00544 #define MAXMSGLIMIT 9999
00545
00546 #define MINPASSWORD 0
00547
00548 #define BASELINELEN 72
00549 #define BASEMAXINLINE 256
00550 #ifdef IMAP_STORAGE
00551 #define ENDL "\r\n"
00552 #else
00553 #define ENDL "\n"
00554 #endif
00555
00556 #define MAX_DATETIME_FORMAT 512
00557 #define MAX_NUM_CID_CONTEXTS 10
00558
00559 #define VM_REVIEW (1 << 0)
00560 #define VM_OPERATOR (1 << 1)
00561 #define VM_SAYCID (1 << 2)
00562 #define VM_SVMAIL (1 << 3)
00563 #define VM_ENVELOPE (1 << 4)
00564 #define VM_SAYDURATION (1 << 5)
00565 #define VM_SKIPAFTERCMD (1 << 6)
00566 #define VM_FORCENAME (1 << 7)
00567 #define VM_FORCEGREET (1 << 8)
00568 #define VM_PBXSKIP (1 << 9)
00569 #define VM_DIRECFORWARD (1 << 10)
00570 #define VM_ATTACH (1 << 11)
00571 #define VM_DELETE (1 << 12)
00572 #define VM_ALLOCED (1 << 13)
00573 #define VM_SEARCH (1 << 14)
00574 #define VM_TEMPGREETWARN (1 << 15)
00575 #define VM_MOVEHEARD (1 << 16)
00576 #define VM_MESSAGEWRAP (1 << 17)
00577 #define VM_FWDURGAUTO (1 << 18)
00578 #define ERROR_LOCK_PATH -100
00579 #define OPERATOR_EXIT 300
00580
00581 enum vm_box {
00582 NEW_FOLDER,
00583 OLD_FOLDER,
00584 WORK_FOLDER,
00585 FAMILY_FOLDER,
00586 FRIENDS_FOLDER,
00587 GREETINGS_FOLDER
00588 };
00589
00590 enum vm_option_flags {
00591 OPT_SILENT = (1 << 0),
00592 OPT_BUSY_GREETING = (1 << 1),
00593 OPT_UNAVAIL_GREETING = (1 << 2),
00594 OPT_RECORDGAIN = (1 << 3),
00595 OPT_PREPEND_MAILBOX = (1 << 4),
00596 OPT_AUTOPLAY = (1 << 6),
00597 OPT_DTMFEXIT = (1 << 7),
00598 OPT_MESSAGE_Urgent = (1 << 8),
00599 OPT_MESSAGE_PRIORITY = (1 << 9)
00600 };
00601
00602 enum vm_option_args {
00603 OPT_ARG_RECORDGAIN = 0,
00604 OPT_ARG_PLAYFOLDER = 1,
00605 OPT_ARG_DTMFEXIT = 2,
00606
00607 OPT_ARG_ARRAY_SIZE = 3,
00608 };
00609
00610 enum vm_passwordlocation {
00611 OPT_PWLOC_VOICEMAILCONF = 0,
00612 OPT_PWLOC_SPOOLDIR = 1,
00613 OPT_PWLOC_USERSCONF = 2,
00614 };
00615
00616 AST_APP_OPTIONS(vm_app_options, {
00617 AST_APP_OPTION('s', OPT_SILENT),
00618 AST_APP_OPTION('b', OPT_BUSY_GREETING),
00619 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
00620 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
00621 AST_APP_OPTION_ARG('d', OPT_DTMFEXIT, OPT_ARG_DTMFEXIT),
00622 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
00623 AST_APP_OPTION_ARG('a', OPT_AUTOPLAY, OPT_ARG_PLAYFOLDER),
00624 AST_APP_OPTION('U', OPT_MESSAGE_Urgent),
00625 AST_APP_OPTION('P', OPT_MESSAGE_PRIORITY)
00626 });
00627
00628 static const char * const mailbox_folders[] = {
00629 #ifdef IMAP_STORAGE
00630 imapfolder,
00631 #else
00632 "INBOX",
00633 #endif
00634 "Old",
00635 "Work",
00636 "Family",
00637 "Friends",
00638 "Cust1",
00639 "Cust2",
00640 "Cust3",
00641 "Cust4",
00642 "Cust5",
00643 "Deleted",
00644 "Urgent",
00645 };
00646
00647 static int load_config(int reload);
00648 #ifdef TEST_FRAMEWORK
00649 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00650 #endif
00651 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg);
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736 struct baseio {
00737 int iocp;
00738 int iolen;
00739 int linelength;
00740 int ateof;
00741 unsigned char iobuf[BASEMAXINLINE];
00742 };
00743
00744
00745
00746 struct ast_vm_user {
00747 char context[AST_MAX_CONTEXT];
00748 char mailbox[AST_MAX_EXTENSION];
00749 char password[80];
00750 char fullname[80];
00751 char email[80];
00752 char *emailsubject;
00753 char *emailbody;
00754 char pager[80];
00755 char serveremail[80];
00756 char language[MAX_LANGUAGE];
00757 char zonetag[80];
00758 char locale[20];
00759 char callback[80];
00760 char dialout[80];
00761 char uniqueid[80];
00762 char exit[80];
00763 char attachfmt[20];
00764 unsigned int flags;
00765 int saydurationm;
00766 int minsecs;
00767 int maxmsg;
00768 int maxdeletedmsg;
00769 int maxsecs;
00770 int passwordlocation;
00771 #ifdef IMAP_STORAGE
00772 char imapserver[48];
00773 char imapport[8];
00774 char imapflags[128];
00775 char imapuser[80];
00776 char imappassword[80];
00777 char imapfolder[64];
00778 char imapvmshareid[80];
00779 int imapversion;
00780 #endif
00781 double volgain;
00782 AST_LIST_ENTRY(ast_vm_user) list;
00783 };
00784
00785
00786 struct vm_zone {
00787 AST_LIST_ENTRY(vm_zone) list;
00788 char name[80];
00789 char timezone[80];
00790 char msg_format[512];
00791 };
00792
00793 #define VMSTATE_MAX_MSG_ARRAY 256
00794
00795
00796 struct vm_state {
00797 char curbox[80];
00798 char username[80];
00799 char context[80];
00800 char curdir[PATH_MAX];
00801 char vmbox[PATH_MAX];
00802 char fn[PATH_MAX];
00803 char intro[PATH_MAX];
00804 int *deleted;
00805 int *heard;
00806 int dh_arraysize;
00807 int curmsg;
00808 int lastmsg;
00809 int newmessages;
00810 int oldmessages;
00811 int urgentmessages;
00812 int starting;
00813 int repeats;
00814 #ifdef IMAP_STORAGE
00815 ast_mutex_t lock;
00816 int updated;
00817 long msgArray[VMSTATE_MAX_MSG_ARRAY];
00818 MAILSTREAM *mailstream;
00819 int vmArrayIndex;
00820 char imapuser[80];
00821 char imapfolder[64];
00822 char imapserver[48];
00823 char imapport[8];
00824 char imapflags[128];
00825 int imapversion;
00826 int interactive;
00827 char introfn[PATH_MAX];
00828 unsigned int quota_limit;
00829 unsigned int quota_usage;
00830 struct vm_state *persist_vms;
00831 #endif
00832 };
00833
00834 #ifdef ODBC_STORAGE
00835 static char odbc_database[80];
00836 static char odbc_table[80];
00837 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
00838 #define DISPOSE(a,b) remove_file(a,b)
00839 #define STORE(a,b,c,d,e,f,g,h,i,j,k) store_file(a,b,c,d)
00840 #define EXISTS(a,b,c,d) (message_exists(a,b))
00841 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
00842 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
00843 #define DELETE(a,b,c,d) (delete_file(a,b))
00844 #define UPDATE_MSG_ID(a, b, c, d, e, f) (odbc_update_msg_id((a), (b), (c)))
00845 #else
00846 #ifdef IMAP_STORAGE
00847 #define DISPOSE(a,b) (imap_remove_file(a,b))
00848 #define STORE(a,b,c,d,e,f,g,h,i,j,k) (imap_store_file(a,b,c,d,e,f,g,h,i,j,k))
00849 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
00850 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00851 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00852 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
00853 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
00854 #define UPDATE_MSG_ID(a, b, c, d, e, f) (vm_imap_update_msg_id((a), (b), (c), (d), (e), (f)))
00855 #else
00856 #define RETRIEVE(a,b,c,d)
00857 #define DISPOSE(a,b)
00858 #define STORE(a,b,c,d,e,f,g,h,i,j,k)
00859 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
00860 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
00861 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
00862 #define DELETE(a,b,c,d) (vm_delete(c))
00863 #define UPDATE_MSG_ID(a, b, c, d, e, f)
00864 #endif
00865 #endif
00866
00867 static char VM_SPOOL_DIR[PATH_MAX];
00868
00869 static char ext_pass_cmd[128];
00870 static char ext_pass_check_cmd[128];
00871
00872 static int my_umask;
00873
00874 #define PWDCHANGE_INTERNAL (1 << 1)
00875 #define PWDCHANGE_EXTERNAL (1 << 2)
00876 static int pwdchange = PWDCHANGE_INTERNAL;
00877
00878 #ifdef ODBC_STORAGE
00879 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
00880 #else
00881 # ifdef IMAP_STORAGE
00882 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
00883 # else
00884 # define tdesc "Comedian Mail (Voicemail System)"
00885 # endif
00886 #endif
00887
00888 static char userscontext[AST_MAX_EXTENSION] = "default";
00889
00890 static char *addesc = "Comedian Mail";
00891
00892
00893 static char *app = "VoiceMail";
00894
00895
00896 static char *app2 = "VoiceMailMain";
00897
00898 static char *app3 = "MailboxExists";
00899 static char *app4 = "VMAuthenticate";
00900
00901 static char *playmsg_app = "VoiceMailPlayMsg";
00902
00903 static char *sayname_app = "VMSayName";
00904
00905 static AST_LIST_HEAD_STATIC(users, ast_vm_user);
00906 static AST_LIST_HEAD_STATIC(zones, vm_zone);
00907 static char zonetag[80];
00908 static char locale[20];
00909 static int maxsilence;
00910 static int maxmsg;
00911 static int maxdeletedmsg;
00912 static int silencethreshold = 128;
00913 static char serveremail[80];
00914 static char mailcmd[160];
00915 static char externnotify[160];
00916 static struct ast_smdi_interface *smdi_iface = NULL;
00917 static char vmfmts[80];
00918 static double volgain;
00919 static int vmminsecs;
00920 static int vmmaxsecs;
00921 static int maxgreet;
00922 static int skipms;
00923 static int maxlogins;
00924 static int minpassword;
00925 static int passwordlocation;
00926
00927
00928
00929 static unsigned int poll_mailboxes;
00930
00931
00932 static unsigned int poll_freq;
00933
00934 #define DEFAULT_POLL_FREQ 30
00935
00936 AST_MUTEX_DEFINE_STATIC(poll_lock);
00937 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
00938 static pthread_t poll_thread = AST_PTHREADT_NULL;
00939 static unsigned char poll_thread_run;
00940
00941
00942 static struct ast_event_sub *mwi_sub_sub;
00943
00944 static struct ast_event_sub *mwi_unsub_sub;
00945
00946
00947
00948
00949
00950
00951
00952
00953 struct mwi_sub {
00954 AST_RWLIST_ENTRY(mwi_sub) entry;
00955 int old_urgent;
00956 int old_new;
00957 int old_old;
00958 uint32_t uniqueid;
00959 char mailbox[1];
00960 };
00961
00962 struct mwi_sub_task {
00963 const char *mailbox;
00964 const char *context;
00965 uint32_t uniqueid;
00966 };
00967
00968 static struct ast_taskprocessor *mwi_subscription_tps;
00969
00970 static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
00971
00972
00973 static char listen_control_forward_key[12];
00974 static char listen_control_reverse_key[12];
00975 static char listen_control_pause_key[12];
00976 static char listen_control_restart_key[12];
00977 static char listen_control_stop_key[12];
00978
00979
00980 static char vm_password[80] = "vm-password";
00981 static char vm_newpassword[80] = "vm-newpassword";
00982 static char vm_passchanged[80] = "vm-passchanged";
00983 static char vm_reenterpassword[80] = "vm-reenterpassword";
00984 static char vm_mismatch[80] = "vm-mismatch";
00985 static char vm_invalid_password[80] = "vm-invalid-password";
00986 static char vm_pls_try_again[80] = "vm-pls-try-again";
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998 static char vm_prepend_timeout[80] = "vm-then-pound";
00999
01000 static struct ast_flags globalflags = {0};
01001
01002 static int saydurationminfo;
01003
01004 static char dialcontext[AST_MAX_CONTEXT] = "";
01005 static char callcontext[AST_MAX_CONTEXT] = "";
01006 static char exitcontext[AST_MAX_CONTEXT] = "";
01007
01008 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
01009
01010
01011 static char *emailbody = NULL;
01012 static char *emailsubject = NULL;
01013 static char *pagerbody = NULL;
01014 static char *pagersubject = NULL;
01015 static char fromstring[100];
01016 static char pagerfromstring[100];
01017 static char charset[32] = "ISO-8859-1";
01018
01019 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
01020 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
01021 static int adsiver = 1;
01022 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
01023 static char pagerdateformat[32] = "%A, %B %d, %Y at %r";
01024
01025
01026 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box);
01027 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu);
01028 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);
01029 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
01030 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
01031 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
01032 signed char record_gain, struct vm_state *vms, char *flag, const char *msg_id);
01033 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
01034 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
01035 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);
01036 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, const char *msg_id);
01037 static void apply_options(struct ast_vm_user *vmu, const char *options);
01038 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);
01039 static int is_valid_dtmf(const char *key);
01040 static void read_password_from_file(const char *secretfn, char *password, int passwordlen);
01041 static int write_password_to_file(const char *secretfn, const char *password);
01042 static const char *substitute_escapes(const char *value);
01043 static int message_range_and_existence_check(struct vm_state *vms, const char *msg_ids [], size_t num_msgs, int *msg_nums, struct ast_vm_user *vmu);
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box, int *newmsg, int move);
01059
01060 static struct ast_vm_mailbox_snapshot *vm_mailbox_snapshot_create(const char *mailbox, const char *context, const char *folder, int descending, enum ast_vm_snapshot_sort_val sort_val, int combine_INBOX_and_OLD);
01061 static struct ast_vm_mailbox_snapshot *vm_mailbox_snapshot_destroy(struct ast_vm_mailbox_snapshot *mailbox_snapshot);
01062
01063 static int vm_msg_forward(const char *from_mailbox, const char *from_context, const char *from_folder, const char *to_mailbox, const char *to_context, const char *to_folder, size_t num_msgs, const char *msg_ids[], int delete_old);
01064 static int vm_msg_move(const char *mailbox, const char *context, size_t num_msgs, const char *oldfolder, const char *old_msg_ids[], const char *newfolder);
01065 static int vm_msg_remove(const char *mailbox, const char *context, size_t num_msgs, const char *folder, const char *msgs[]);
01066 static int vm_msg_play(struct ast_channel *chan, const char *mailbox, const char *context, const char *folder, const char *msg_num, ast_vm_msg_play_cb cb);
01067
01068 #ifdef TEST_FRAMEWORK
01069 static int vm_test_destroy_user(const char *context, const char *mailbox);
01070 static int vm_test_create_user(const char *context, const char *mailbox);
01071 #endif
01072
01073 struct ao2_container *inprocess_container;
01074
01075 struct inprocess {
01076 int count;
01077 char *context;
01078 char mailbox[0];
01079 };
01080
01081 static int inprocess_hash_fn(const void *obj, const int flags)
01082 {
01083 const struct inprocess *i = obj;
01084 return atoi(i->mailbox);
01085 }
01086
01087 static int inprocess_cmp_fn(void *obj, void *arg, int flags)
01088 {
01089 struct inprocess *i = obj, *j = arg;
01090 if (strcmp(i->mailbox, j->mailbox)) {
01091 return 0;
01092 }
01093 return !strcmp(i->context, j->context) ? CMP_MATCH : 0;
01094 }
01095
01096 static int inprocess_count(const char *context, const char *mailbox, int delta)
01097 {
01098 struct inprocess *i, *arg = ast_alloca(sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
01099 arg->context = arg->mailbox + strlen(mailbox) + 1;
01100 strcpy(arg->mailbox, mailbox);
01101 strcpy(arg->context, context);
01102 ao2_lock(inprocess_container);
01103 if ((i = ao2_find(inprocess_container, arg, 0))) {
01104 int ret = ast_atomic_fetchadd_int(&i->count, delta);
01105 ao2_unlock(inprocess_container);
01106 ao2_ref(i, -1);
01107 return ret;
01108 }
01109 if (delta < 0) {
01110 ast_log(LOG_WARNING, "BUG: ref count decrement on non-existing object???\n");
01111 }
01112 if (!(i = ao2_alloc(sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
01113 ao2_unlock(inprocess_container);
01114 return 0;
01115 }
01116 i->context = i->mailbox + strlen(mailbox) + 1;
01117 strcpy(i->mailbox, mailbox);
01118 strcpy(i->context, context);
01119 i->count = delta;
01120 ao2_link(inprocess_container, i);
01121 ao2_unlock(inprocess_container);
01122 ao2_ref(i, -1);
01123 return 0;
01124 }
01125
01126 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
01127 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit);
01128 #endif
01129
01130
01131
01132
01133
01134
01135
01136 static char *strip_control_and_high(const char *input, char *buf, size_t buflen)
01137 {
01138 char *bufptr = buf;
01139 for (; *input; input++) {
01140 if (*input < 32) {
01141 continue;
01142 }
01143 *bufptr++ = *input;
01144 if (bufptr == buf + buflen - 1) {
01145 break;
01146 }
01147 }
01148 *bufptr = '\0';
01149 return buf;
01150 }
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166 static void populate_defaults(struct ast_vm_user *vmu)
01167 {
01168 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
01169 vmu->passwordlocation = passwordlocation;
01170 if (saydurationminfo) {
01171 vmu->saydurationm = saydurationminfo;
01172 }
01173 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
01174 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
01175 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
01176 ast_copy_string(vmu->zonetag, zonetag, sizeof(vmu->zonetag));
01177 ast_copy_string(vmu->locale, locale, sizeof(vmu->locale));
01178 if (vmminsecs) {
01179 vmu->minsecs = vmminsecs;
01180 }
01181 if (vmmaxsecs) {
01182 vmu->maxsecs = vmmaxsecs;
01183 }
01184 if (maxmsg) {
01185 vmu->maxmsg = maxmsg;
01186 }
01187 if (maxdeletedmsg) {
01188 vmu->maxdeletedmsg = maxdeletedmsg;
01189 }
01190 vmu->volgain = volgain;
01191 ast_free(vmu->emailsubject);
01192 vmu->emailsubject = NULL;
01193 ast_free(vmu->emailbody);
01194 vmu->emailbody = NULL;
01195 #ifdef IMAP_STORAGE
01196 ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
01197 ast_copy_string(vmu->imapserver, imapserver, sizeof(vmu->imapserver));
01198 ast_copy_string(vmu->imapport, imapport, sizeof(vmu->imapport));
01199 ast_copy_string(vmu->imapflags, imapflags, sizeof(vmu->imapflags));
01200 #endif
01201 }
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
01212 {
01213 int x;
01214 if (!strcasecmp(var, "attach")) {
01215 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
01216 } else if (!strcasecmp(var, "attachfmt")) {
01217 ast_copy_string(vmu->attachfmt, value, sizeof(vmu->attachfmt));
01218 } else if (!strcasecmp(var, "serveremail")) {
01219 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
01220 } else if (!strcasecmp(var, "emailbody")) {
01221 ast_free(vmu->emailbody);
01222 vmu->emailbody = ast_strdup(substitute_escapes(value));
01223 } else if (!strcasecmp(var, "emailsubject")) {
01224 ast_free(vmu->emailsubject);
01225 vmu->emailsubject = ast_strdup(substitute_escapes(value));
01226 } else if (!strcasecmp(var, "language")) {
01227 ast_copy_string(vmu->language, value, sizeof(vmu->language));
01228 } else if (!strcasecmp(var, "tz")) {
01229 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
01230 } else if (!strcasecmp(var, "locale")) {
01231 ast_copy_string(vmu->locale, value, sizeof(vmu->locale));
01232 #ifdef IMAP_STORAGE
01233 } else if (!strcasecmp(var, "imapuser")) {
01234 ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
01235 vmu->imapversion = imapversion;
01236 } else if (!strcasecmp(var, "imapserver")) {
01237 ast_copy_string(vmu->imapserver, value, sizeof(vmu->imapserver));
01238 vmu->imapversion = imapversion;
01239 } else if (!strcasecmp(var, "imapport")) {
01240 ast_copy_string(vmu->imapport, value, sizeof(vmu->imapport));
01241 vmu->imapversion = imapversion;
01242 } else if (!strcasecmp(var, "imapflags")) {
01243 ast_copy_string(vmu->imapflags, value, sizeof(vmu->imapflags));
01244 vmu->imapversion = imapversion;
01245 } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
01246 ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
01247 vmu->imapversion = imapversion;
01248 } else if (!strcasecmp(var, "imapfolder")) {
01249 ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
01250 vmu->imapversion = imapversion;
01251 } else if (!strcasecmp(var, "imapvmshareid")) {
01252 ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
01253 vmu->imapversion = imapversion;
01254 #endif
01255 } else if (!strcasecmp(var, "delete") || !strcasecmp(var, "deletevoicemail")) {
01256 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
01257 } else if (!strcasecmp(var, "saycid")){
01258 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
01259 } else if (!strcasecmp(var, "sendvoicemail")){
01260 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
01261 } else if (!strcasecmp(var, "review")){
01262 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
01263 } else if (!strcasecmp(var, "tempgreetwarn")){
01264 ast_set2_flag(vmu, ast_true(value), VM_TEMPGREETWARN);
01265 } else if (!strcasecmp(var, "messagewrap")){
01266 ast_set2_flag(vmu, ast_true(value), VM_MESSAGEWRAP);
01267 } else if (!strcasecmp(var, "operator")) {
01268 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
01269 } else if (!strcasecmp(var, "envelope")){
01270 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
01271 } else if (!strcasecmp(var, "moveheard")){
01272 ast_set2_flag(vmu, ast_true(value), VM_MOVEHEARD);
01273 } else if (!strcasecmp(var, "sayduration")){
01274 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
01275 } else if (!strcasecmp(var, "saydurationm")){
01276 if (sscanf(value, "%30d", &x) == 1) {
01277 vmu->saydurationm = x;
01278 } else {
01279 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
01280 }
01281 } else if (!strcasecmp(var, "forcename")){
01282 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
01283 } else if (!strcasecmp(var, "forcegreetings")){
01284 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
01285 } else if (!strcasecmp(var, "callback")) {
01286 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
01287 } else if (!strcasecmp(var, "dialout")) {
01288 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
01289 } else if (!strcasecmp(var, "exitcontext")) {
01290 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
01291 } else if (!strcasecmp(var, "minsecs")) {
01292 if (sscanf(value, "%30d", &x) == 1 && x >= 0) {
01293 vmu->minsecs = x;
01294 } else {
01295 ast_log(LOG_WARNING, "Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
01296 vmu->minsecs = vmminsecs;
01297 }
01298 } else if (!strcasecmp(var, "maxmessage") || !strcasecmp(var, "maxsecs")) {
01299 vmu->maxsecs = atoi(value);
01300 if (vmu->maxsecs <= 0) {
01301 ast_log(AST_LOG_WARNING, "Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
01302 vmu->maxsecs = vmmaxsecs;
01303 } else {
01304 vmu->maxsecs = atoi(value);
01305 }
01306 if (!strcasecmp(var, "maxmessage"))
01307 ast_log(AST_LOG_WARNING, "Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
01308 } else if (!strcasecmp(var, "maxmsg")) {
01309 vmu->maxmsg = atoi(value);
01310
01311 if (vmu->maxmsg < 0) {
01312 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
01313 vmu->maxmsg = MAXMSG;
01314 } else if (vmu->maxmsg > MAXMSGLIMIT) {
01315 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
01316 vmu->maxmsg = MAXMSGLIMIT;
01317 }
01318 } else if (!strcasecmp(var, "nextaftercmd")) {
01319 ast_set2_flag(vmu, ast_true(value), VM_SKIPAFTERCMD);
01320 } else if (!strcasecmp(var, "backupdeleted")) {
01321 if (sscanf(value, "%30d", &x) == 1)
01322 vmu->maxdeletedmsg = x;
01323 else if (ast_true(value))
01324 vmu->maxdeletedmsg = MAXMSG;
01325 else
01326 vmu->maxdeletedmsg = 0;
01327
01328 if (vmu->maxdeletedmsg < 0) {
01329 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
01330 vmu->maxdeletedmsg = MAXMSG;
01331 } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) {
01332 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
01333 vmu->maxdeletedmsg = MAXMSGLIMIT;
01334 }
01335 } else if (!strcasecmp(var, "volgain")) {
01336 sscanf(value, "%30lf", &vmu->volgain);
01337 } else if (!strcasecmp(var, "passwordlocation")) {
01338 if (!strcasecmp(value, "spooldir")) {
01339 vmu->passwordlocation = OPT_PWLOC_SPOOLDIR;
01340 } else {
01341 vmu->passwordlocation = OPT_PWLOC_VOICEMAILCONF;
01342 }
01343 } else if (!strcasecmp(var, "options")) {
01344 apply_options(vmu, value);
01345 }
01346 }
01347
01348 static char *vm_check_password_shell(char *command, char *buf, size_t len)
01349 {
01350 int fds[2], pid = 0;
01351
01352 memset(buf, 0, len);
01353
01354 if (pipe(fds)) {
01355 snprintf(buf, len, "FAILURE: Pipe failed: %s", strerror(errno));
01356 } else {
01357
01358 pid = ast_safe_fork(0);
01359
01360 if (pid < 0) {
01361
01362 close(fds[0]);
01363 close(fds[1]);
01364 snprintf(buf, len, "FAILURE: Fork failed");
01365 } else if (pid) {
01366
01367 close(fds[1]);
01368 if (read(fds[0], buf, len) < 0) {
01369 ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
01370 }
01371 close(fds[0]);
01372 } else {
01373
01374 AST_DECLARE_APP_ARGS(arg,
01375 AST_APP_ARG(v)[20];
01376 );
01377 char *mycmd = ast_strdupa(command);
01378
01379 close(fds[0]);
01380 dup2(fds[1], STDOUT_FILENO);
01381 close(fds[1]);
01382 ast_close_fds_above_n(STDOUT_FILENO);
01383
01384 AST_NONSTANDARD_APP_ARGS(arg, mycmd, ' ');
01385
01386 execv(arg.v[0], arg.v);
01387 printf("FAILURE: %s", strerror(errno));
01388 _exit(0);
01389 }
01390 }
01391 return buf;
01392 }
01393
01394
01395
01396
01397
01398
01399
01400
01401 static int check_password(struct ast_vm_user *vmu, char *password)
01402 {
01403
01404 if (strlen(password) < minpassword)
01405 return 1;
01406
01407 if (!ast_strlen_zero(password) && password[0] == '*')
01408 return 1;
01409 if (!ast_strlen_zero(ext_pass_check_cmd)) {
01410 char cmd[255], buf[255];
01411
01412 ast_debug(1, "Verify password policies for %s\n", password);
01413
01414 snprintf(cmd, sizeof(cmd), "%s %s %s %s %s", ext_pass_check_cmd, vmu->mailbox, vmu->context, vmu->password, password);
01415 if (vm_check_password_shell(cmd, buf, sizeof(buf))) {
01416 ast_debug(5, "Result: %s\n", buf);
01417 if (!strncasecmp(buf, "VALID", 5)) {
01418 ast_debug(3, "Passed password check: '%s'\n", buf);
01419 return 0;
01420 } else if (!strncasecmp(buf, "FAILURE", 7)) {
01421 ast_log(AST_LOG_WARNING, "Unable to execute password validation script: '%s'.\n", buf);
01422 return 0;
01423 } else {
01424 ast_log(AST_LOG_NOTICE, "Password doesn't match policies for user %s %s\n", vmu->mailbox, password);
01425 return 1;
01426 }
01427 }
01428 }
01429 return 0;
01430 }
01431
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
01443 {
01444 int res = -1;
01445 if (!strcmp(vmu->password, password)) {
01446
01447 return 0;
01448 }
01449
01450 if (strlen(password) > 10) {
01451 ast_realtime_require_field("voicemail", "password", RQ_CHAR, strlen(password), SENTINEL);
01452 }
01453 if (ast_update2_realtime("voicemail", "context", vmu->context, "mailbox", vmu->mailbox, SENTINEL, "password", password, SENTINEL) > 0) {
01454 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: realtime engine updated with new password\r\nPasswordSource: realtime");
01455 ast_copy_string(vmu->password, password, sizeof(vmu->password));
01456 res = 0;
01457 }
01458 return res;
01459 }
01460
01461
01462
01463
01464 static void apply_options(struct ast_vm_user *vmu, const char *options)
01465 {
01466 char *stringp;
01467 char *s;
01468 char *var, *value;
01469 stringp = ast_strdupa(options);
01470 while ((s = strsep(&stringp, "|"))) {
01471 value = s;
01472 if ((var = strsep(&value, "=")) && value) {
01473 apply_option(vmu, var, value);
01474 }
01475 }
01476 }
01477
01478
01479
01480
01481
01482
01483 static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
01484 {
01485 for (; var; var = var->next) {
01486 if (!strcasecmp(var->name, "vmsecret")) {
01487 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01488 } else if (!strcasecmp(var->name, "secret") || !strcasecmp(var->name, "password")) {
01489 if (ast_strlen_zero(retval->password)) {
01490 if (!ast_strlen_zero(var->value) && var->value[0] == '*') {
01491 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
01492 "\n\tmust be reset in voicemail.conf.\n", retval->mailbox);
01493 } else {
01494 ast_copy_string(retval->password, var->value, sizeof(retval->password));
01495 }
01496 }
01497 } else if (!strcasecmp(var->name, "uniqueid")) {
01498 ast_copy_string(retval->uniqueid, var->value, sizeof(retval->uniqueid));
01499 } else if (!strcasecmp(var->name, "pager")) {
01500 ast_copy_string(retval->pager, var->value, sizeof(retval->pager));
01501 } else if (!strcasecmp(var->name, "email")) {
01502 ast_copy_string(retval->email, var->value, sizeof(retval->email));
01503 } else if (!strcasecmp(var->name, "fullname")) {
01504 ast_copy_string(retval->fullname, var->value, sizeof(retval->fullname));
01505 } else if (!strcasecmp(var->name, "context")) {
01506 ast_copy_string(retval->context, var->value, sizeof(retval->context));
01507 } else if (!strcasecmp(var->name, "emailsubject")) {
01508 ast_free(retval->emailsubject);
01509 retval->emailsubject = ast_strdup(substitute_escapes(var->value));
01510 } else if (!strcasecmp(var->name, "emailbody")) {
01511 ast_free(retval->emailbody);
01512 retval->emailbody = ast_strdup(substitute_escapes(var->value));
01513 #ifdef IMAP_STORAGE
01514 } else if (!strcasecmp(var->name, "imapuser")) {
01515 ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
01516 retval->imapversion = imapversion;
01517 } else if (!strcasecmp(var->name, "imapserver")) {
01518 ast_copy_string(retval->imapserver, var->value, sizeof(retval->imapserver));
01519 retval->imapversion = imapversion;
01520 } else if (!strcasecmp(var->name, "imapport")) {
01521 ast_copy_string(retval->imapport, var->value, sizeof(retval->imapport));
01522 retval->imapversion = imapversion;
01523 } else if (!strcasecmp(var->name, "imapflags")) {
01524 ast_copy_string(retval->imapflags, var->value, sizeof(retval->imapflags));
01525 retval->imapversion = imapversion;
01526 } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
01527 ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
01528 retval->imapversion = imapversion;
01529 } else if (!strcasecmp(var->name, "imapfolder")) {
01530 ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
01531 retval->imapversion = imapversion;
01532 } else if (!strcasecmp(var->name, "imapvmshareid")) {
01533 ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
01534 retval->imapversion = imapversion;
01535 #endif
01536 } else
01537 apply_option(retval, var->name, var->value);
01538 }
01539 }
01540
01541
01542
01543
01544
01545
01546
01547
01548 static int is_valid_dtmf(const char *key)
01549 {
01550 int i;
01551 char *local_key = ast_strdupa(key);
01552
01553 for (i = 0; i < strlen(key); ++i) {
01554 if (!strchr(VALID_DTMF, *local_key)) {
01555 ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
01556 return 0;
01557 }
01558 local_key++;
01559 }
01560 return 1;
01561 }
01562
01563
01564
01565
01566
01567
01568
01569
01570
01571
01572
01573 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01574 {
01575 struct ast_variable *var;
01576 struct ast_vm_user *retval;
01577
01578 if ((retval = (ivm ? ivm : ast_calloc(1, sizeof(*retval))))) {
01579 if (ivm) {
01580 memset(retval, 0, sizeof(*retval));
01581 }
01582 populate_defaults(retval);
01583 if (!ivm) {
01584 ast_set_flag(retval, VM_ALLOCED);
01585 }
01586 if (mailbox) {
01587 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
01588 }
01589 if (!context && ast_test_flag((&globalflags), VM_SEARCH)) {
01590 var = ast_load_realtime("voicemail", "mailbox", mailbox, SENTINEL);
01591 } else {
01592 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", context, SENTINEL);
01593 }
01594 if (var) {
01595 apply_options_full(retval, var);
01596 ast_variables_destroy(var);
01597 } else {
01598 if (!ivm)
01599 ast_free(retval);
01600 retval = NULL;
01601 }
01602 }
01603 return retval;
01604 }
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
01615 {
01616
01617 struct ast_vm_user *vmu = NULL, *cur;
01618 AST_LIST_LOCK(&users);
01619
01620 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
01621 context = "default";
01622
01623 AST_LIST_TRAVERSE(&users, cur, list) {
01624 #ifdef IMAP_STORAGE
01625 if (cur->imapversion != imapversion) {
01626 continue;
01627 }
01628 #endif
01629 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
01630 break;
01631 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
01632 break;
01633 }
01634 if (cur) {
01635
01636 if ((vmu = (ivm ? ivm : ast_malloc(sizeof(*vmu))))) {
01637 *vmu = *cur;
01638 if (!ivm) {
01639 vmu->emailbody = ast_strdup(cur->emailbody);
01640 vmu->emailsubject = ast_strdup(cur->emailsubject);
01641 }
01642 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
01643 AST_LIST_NEXT(vmu, list) = NULL;
01644 }
01645 } else
01646 vmu = find_user_realtime(ivm, context, mailbox);
01647 AST_LIST_UNLOCK(&users);
01648 return vmu;
01649 }
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
01662 {
01663
01664 struct ast_vm_user *cur;
01665 int res = -1;
01666 AST_LIST_LOCK(&users);
01667 AST_LIST_TRAVERSE(&users, cur, list) {
01668 if ((!context || !strcasecmp(context, cur->context)) &&
01669 (!strcasecmp(mailbox, cur->mailbox)))
01670 break;
01671 }
01672 if (cur) {
01673 ast_copy_string(cur->password, newpass, sizeof(cur->password));
01674 res = 0;
01675 }
01676 AST_LIST_UNLOCK(&users);
01677 return res;
01678 }
01679
01680
01681
01682
01683 static inline int valid_config(const struct ast_config *cfg)
01684 {
01685 return cfg && cfg != CONFIG_STATUS_FILEINVALID;
01686 }
01687
01688
01689
01690
01691
01692
01693
01694
01695 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
01696 {
01697 struct ast_config *cfg = NULL;
01698 struct ast_variable *var = NULL;
01699 struct ast_category *cat = NULL;
01700 char *category = NULL, *value = NULL, *new = NULL;
01701 const char *tmp = NULL;
01702 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
01703 char secretfn[PATH_MAX] = "";
01704 int found = 0;
01705
01706 if (!change_password_realtime(vmu, newpassword))
01707 return;
01708
01709
01710 switch (vmu->passwordlocation) {
01711 case OPT_PWLOC_SPOOLDIR:
01712 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
01713 if (write_password_to_file(secretfn, newpassword) == 0) {
01714 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: secret.conf updated with new password\r\nPasswordSource: secret.conf");
01715 ast_verb(4, "Writing voicemail password to file %s succeeded\n", secretfn);
01716 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01717 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01718 break;
01719 } else {
01720 ast_verb(4, "Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
01721 }
01722
01723 case OPT_PWLOC_VOICEMAILCONF:
01724 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) && valid_config(cfg)) {
01725 while ((category = ast_category_browse(cfg, category))) {
01726 if (!strcasecmp(category, vmu->context)) {
01727 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->mailbox))) {
01728 ast_log(AST_LOG_WARNING, "We could not find the mailbox.\n");
01729 break;
01730 }
01731 value = strstr(tmp, ",");
01732 if (!value) {
01733 new = ast_alloca(strlen(newpassword)+1);
01734 sprintf(new, "%s", newpassword);
01735 } else {
01736 new = ast_alloca((strlen(value) + strlen(newpassword) + 1));
01737 sprintf(new, "%s%s", newpassword, value);
01738 }
01739 if (!(cat = ast_category_get(cfg, category))) {
01740 ast_log(AST_LOG_WARNING, "Failed to get category structure.\n");
01741 break;
01742 }
01743 ast_variable_update(cat, vmu->mailbox, new, NULL, 0);
01744 found = 1;
01745 }
01746 }
01747
01748 if (found) {
01749 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
01750 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01751 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01752 ast_config_text_file_save(VOICEMAIL_CONFIG, cfg, "AppVoicemail");
01753 ast_config_destroy(cfg);
01754 break;
01755 }
01756
01757 ast_config_destroy(cfg);
01758 }
01759
01760 case OPT_PWLOC_USERSCONF:
01761
01762
01763 if ((cfg = ast_config_load("users.conf", config_flags)) && valid_config(cfg)) {
01764 ast_debug(4, "we are looking for %s\n", vmu->mailbox);
01765 for (category = ast_category_browse(cfg, NULL); category; category = ast_category_browse(cfg, category)) {
01766 ast_debug(4, "users.conf: %s\n", category);
01767 if (!strcasecmp(category, vmu->mailbox)) {
01768 if (!ast_variable_retrieve(cfg, category, "vmsecret")) {
01769 ast_debug(3, "looks like we need to make vmsecret!\n");
01770 var = ast_variable_new("vmsecret", newpassword, "");
01771 } else {
01772 var = NULL;
01773 }
01774 new = ast_alloca(strlen(newpassword) + 1);
01775 sprintf(new, "%s", newpassword);
01776 if (!(cat = ast_category_get(cfg, category))) {
01777 ast_debug(4, "failed to get category!\n");
01778 ast_free(var);
01779 break;
01780 }
01781 if (!var) {
01782 ast_variable_update(cat, "vmsecret", new, NULL, 0);
01783 } else {
01784 ast_variable_append(cat, var);
01785 }
01786 found = 1;
01787 break;
01788 }
01789 }
01790
01791 if (found) {
01792 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: users.conf updated with new password\r\nPasswordSource: users.conf");
01793 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01794 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01795 ast_config_text_file_save("users.conf", cfg, "AppVoicemail");
01796 }
01797
01798 ast_config_destroy(cfg);
01799 }
01800 }
01801 }
01802
01803 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
01804 {
01805 char buf[255];
01806 snprintf(buf, sizeof(buf), "%s %s %s %s", ext_pass_cmd, vmu->context, vmu->mailbox, newpassword);
01807 ast_debug(1, "External password: %s\n",buf);
01808 if (!ast_safe_system(buf)) {
01809 ast_test_suite_event_notify("PASSWORDCHANGED", "Message: external script updated with new password\r\nPasswordSource: external");
01810 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
01811
01812 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
01813 }
01814 }
01815
01816
01817
01818
01819
01820
01821
01822
01823
01824
01825
01826
01827
01828
01829 static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
01830 {
01831 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
01832 }
01833
01834
01835
01836
01837
01838
01839
01840
01841
01842
01843
01844
01845
01846 static int make_file(char *dest, const int len, const char *dir, const int num)
01847 {
01848 return snprintf(dest, len, "%s/msg%04d", dir, num);
01849 }
01850
01851
01852 static FILE *vm_mkftemp(char *template)
01853 {
01854 FILE *p = NULL;
01855 int pfd = mkstemp(template);
01856 chmod(template, VOICEMAIL_FILE_MODE & ~my_umask);
01857 if (pfd > -1) {
01858 p = fdopen(pfd, "w+");
01859 if (!p) {
01860 close(pfd);
01861 pfd = -1;
01862 }
01863 }
01864 return p;
01865 }
01866
01867
01868
01869
01870
01871
01872
01873
01874
01875 static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
01876 {
01877 mode_t mode = VOICEMAIL_DIR_MODE;
01878 int res;
01879
01880 make_dir(dest, len, context, ext, folder);
01881 if ((res = ast_mkdir(dest, mode))) {
01882 ast_log(AST_LOG_WARNING, "ast_mkdir '%s' failed: %s\n", dest, strerror(res));
01883 return -1;
01884 }
01885 return 0;
01886 }
01887
01888 static const char *mbox(struct ast_vm_user *vmu, int id)
01889 {
01890 #ifdef IMAP_STORAGE
01891 if (vmu && id == 0) {
01892 return vmu->imapfolder;
01893 }
01894 #endif
01895 return (id >= 0 && id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] : "Unknown";
01896 }
01897
01898 static const char *vm_index_to_foldername(int id)
01899 {
01900 return mbox(NULL, id);
01901 }
01902
01903
01904 static int get_folder_by_name(const char *name)
01905 {
01906 size_t i;
01907
01908 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
01909 if (strcasecmp(name, mailbox_folders[i]) == 0) {
01910 return i;
01911 }
01912 }
01913
01914 return -1;
01915 }
01916
01917 static void free_user(struct ast_vm_user *vmu)
01918 {
01919 if (ast_test_flag(vmu, VM_ALLOCED)) {
01920
01921 ast_free(vmu->emailbody);
01922 vmu->emailbody = NULL;
01923
01924 ast_free(vmu->emailsubject);
01925 vmu->emailsubject = NULL;
01926
01927 ast_free(vmu);
01928 }
01929 }
01930
01931 static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg) {
01932
01933 int arraysize = (vmu->maxmsg > count_msg ? vmu->maxmsg : count_msg);
01934
01935
01936 if (vms->deleted) {
01937 ast_free(vms->deleted);
01938 vms->deleted = NULL;
01939 }
01940 if (vms->heard) {
01941 ast_free(vms->heard);
01942 vms->heard = NULL;
01943 }
01944 vms->dh_arraysize = 0;
01945
01946 if (arraysize > 0) {
01947 if (!(vms->deleted = ast_calloc(arraysize, sizeof(int)))) {
01948 return -1;
01949 }
01950 if (!(vms->heard = ast_calloc(arraysize, sizeof(int)))) {
01951 ast_free(vms->deleted);
01952 vms->deleted = NULL;
01953 return -1;
01954 }
01955 vms->dh_arraysize = arraysize;
01956 }
01957
01958 return 0;
01959 }
01960
01961
01962
01963 #ifdef IMAP_STORAGE
01964 static void vm_imap_delete(char *file, int msgnum, struct ast_vm_user *vmu)
01965 {
01966 char arg[10];
01967 struct vm_state *vms;
01968 unsigned long messageNum;
01969
01970
01971 if (msgnum < 0 && !imapgreetings) {
01972 ast_filedelete(file, NULL);
01973 return;
01974 }
01975
01976 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
01977 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);
01978 return;
01979 }
01980
01981 if (msgnum < 0) {
01982 imap_delete_old_greeting(file, vms);
01983 return;
01984 }
01985
01986
01987
01988 messageNum = vms->msgArray[msgnum];
01989 if (messageNum == 0) {
01990 ast_log(LOG_WARNING, "msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
01991 return;
01992 }
01993 ast_debug(3, "deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
01994
01995 snprintf (arg, sizeof(arg), "%lu", messageNum);
01996 ast_mutex_lock(&vms->lock);
01997 mail_setflag (vms->mailstream, arg, "\\DELETED");
01998 mail_expunge(vms->mailstream);
01999 ast_mutex_unlock(&vms->lock);
02000 }
02001
02002 static void vm_imap_update_msg_id(char *dir, int msgnum, const char *msg_id, struct ast_vm_user *vmu, struct ast_config *msg_cfg, int folder)
02003 {
02004 struct ast_channel *chan;
02005 char *cid;
02006 char *cid_name;
02007 char *cid_num;
02008 struct vm_state *vms;
02009 const char *duration_str;
02010 int duration = 0;
02011
02012
02013
02014
02015
02016 vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0);
02017 if (!vms) {
02018 return;
02019 }
02020
02021 if (open_mailbox(vms, vmu, folder)) {
02022 return;
02023 }
02024
02025 chan = ast_dummy_channel_alloc();
02026 if (!chan) {
02027 close_mailbox(vms, vmu);
02028 return;
02029 }
02030
02031
02032
02033
02034
02035 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
02036
02037 if (!ast_strlen_zero(cid)) {
02038 ast_callerid_parse(cid, &cid_name, &cid_num);
02039 ast_party_caller_init(ast_channel_caller(chan));
02040 if (!ast_strlen_zero(cid_name)) {
02041 ast_channel_caller(chan)->id.name.valid = 1;
02042 ast_channel_caller(chan)->id.name.str = ast_strdup(cid_name);
02043 }
02044 if (!ast_strlen_zero(cid_num)) {
02045 ast_channel_caller(chan)->id.number.valid = 1;
02046 ast_channel_caller(chan)->id.number.str = ast_strdup(cid_num);
02047 }
02048 }
02049
02050 duration_str = ast_variable_retrieve(msg_cfg, "message", "duration");
02051
02052 if (!ast_strlen_zero(duration_str)) {
02053 sscanf(duration_str, "%30d", &duration);
02054 }
02055
02056
02057
02058
02059
02060
02061
02062
02063
02064 if (!imap_store_file(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, vmfmts,
02065 duration, vms, ast_variable_retrieve(msg_cfg, "message", "flag"), msg_id)) {
02066 if (folder != NEW_FOLDER) {
02067 save_to_folder(vmu, vms, msgnum, folder, NULL, 1);
02068 }
02069 vm_imap_delete(dir, msgnum, vmu);
02070 }
02071 close_mailbox(vms, vmu);
02072 ast_channel_unref(chan);
02073 }
02074
02075 static int imap_retrieve_greeting(const char *dir, const int msgnum, struct ast_vm_user *vmu)
02076 {
02077 struct vm_state *vms_p;
02078 char *file, *filename;
02079 char *attachment;
02080 int i;
02081 BODY *body;
02082
02083
02084
02085
02086 if (msgnum > -1 || !imapgreetings) {
02087 return 0;
02088 } else {
02089 file = strrchr(ast_strdupa(dir), '/');
02090 if (file)
02091 *file++ = '\0';
02092 else {
02093 ast_debug(1, "Failed to procure file name from directory passed.\n");
02094 return -1;
02095 }
02096 }
02097
02098
02099 if (!(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) &&
02100 !(vms_p = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
02101
02102
02103
02104
02105 if (!(vms_p = create_vm_state_from_user(vmu))) {
02106 ast_log(LOG_NOTICE, "Unable to create vm_state object!\n");
02107 return -1;
02108 }
02109 }
02110
02111
02112 *vms_p->introfn = '\0';
02113
02114 ast_mutex_lock(&vms_p->lock);
02115 if (init_mailstream(vms_p, GREETINGS_FOLDER) || !vms_p->mailstream) {
02116 ast_log(AST_LOG_ERROR, "IMAP mailstream is NULL or can't init_mailstream\n");
02117 ast_mutex_unlock(&vms_p->lock);
02118 return -1;
02119 }
02120
02121
02122 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
02123 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
02124
02125 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
02126 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
02127 } else {
02128 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
02129 ast_mutex_unlock(&vms_p->lock);
02130 return -1;
02131 }
02132 filename = strsep(&attachment, ".");
02133 if (!strcmp(filename, file)) {
02134 ast_copy_string(vms_p->fn, dir, sizeof(vms_p->fn));
02135 vms_p->msgArray[vms_p->curmsg] = i + 1;
02136 save_body(body, vms_p, "2", attachment, 0);
02137 ast_mutex_unlock(&vms_p->lock);
02138 return 0;
02139 }
02140 }
02141 ast_mutex_unlock(&vms_p->lock);
02142
02143 return -1;
02144 }
02145
02146 static int imap_retrieve_file(const char *dir, const int msgnum, const char *mailbox, const char *context)
02147 {
02148 BODY *body;
02149 char *header_content;
02150 char *attachedfilefmt;
02151 char buf[80];
02152 struct vm_state *vms;
02153 char text_file[PATH_MAX];
02154 FILE *text_file_ptr;
02155 int res = 0;
02156 struct ast_vm_user *vmu;
02157
02158 if (!(vmu = find_user(NULL, context, mailbox))) {
02159 ast_log(LOG_WARNING, "Couldn't find user with mailbox %s@%s\n", mailbox, context);
02160 return -1;
02161 }
02162
02163 if (msgnum < 0) {
02164 if (imapgreetings) {
02165 res = imap_retrieve_greeting(dir, msgnum, vmu);
02166 goto exit;
02167 } else {
02168 res = 0;
02169 goto exit;
02170 }
02171 }
02172
02173
02174
02175
02176 if (!(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->mailbox, vmu->context, 0))) {
02177
02178
02179
02180
02181
02182
02183
02184 ast_log(LOG_ERROR, "Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->mailbox);
02185 res = -1;
02186 goto exit;
02187 }
02188
02189 make_file(vms->fn, sizeof(vms->fn), dir, msgnum);
02190 snprintf(vms->introfn, sizeof(vms->introfn), "%sintro", vms->fn);
02191
02192
02193 if (ast_fileexists(vms->fn, NULL, NULL) > 0) {
02194 res = 0;
02195 goto exit;
02196 }
02197
02198 ast_debug(3, "Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
02199 if (vms->msgArray[msgnum] == 0) {
02200 ast_log(LOG_WARNING, "Trying to access unknown message\n");
02201 res = -1;
02202 goto exit;
02203 }
02204
02205
02206 ast_mutex_lock(&vms->lock);
02207 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
02208 ast_mutex_unlock(&vms->lock);
02209
02210 if (ast_strlen_zero(header_content)) {
02211 ast_log(LOG_ERROR, "Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
02212 res = -1;
02213 goto exit;
02214 }
02215
02216 ast_mutex_lock(&vms->lock);
02217 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
02218 ast_mutex_unlock(&vms->lock);
02219
02220
02221 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
02222 attachedfilefmt = ast_strdupa(body->nested.part->next->body.parameter->value);
02223 } else {
02224 ast_log(LOG_ERROR, "There is no file attached to this IMAP message.\n");
02225 res = -1;
02226 goto exit;
02227 }
02228
02229
02230
02231 strsep(&attachedfilefmt, ".");
02232 if (!attachedfilefmt) {
02233 ast_log(LOG_ERROR, "File format could not be obtained from IMAP message attachment\n");
02234 res = -1;
02235 goto exit;
02236 }
02237
02238 save_body(body, vms, "2", attachedfilefmt, 0);
02239 if (save_body(body, vms, "3", attachedfilefmt, 1)) {
02240 *vms->introfn = '\0';
02241 }
02242
02243
02244 snprintf(text_file, sizeof(text_file), "%s.%s", vms->fn, "txt");
02245
02246 if (!(text_file_ptr = fopen(text_file, "w"))) {
02247 ast_log(LOG_WARNING, "Unable to open/create file %s: %s\n", text_file, strerror(errno));
02248 }
02249
02250 fprintf(text_file_ptr, "%s\n", "[message]");
02251
02252 if (get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Name:", buf, sizeof(buf))) {
02253 fprintf(text_file_ptr, "callerid=\"%s\" ", S_OR(buf, ""));
02254 }
02255 if (get_header_by_tag(header_content, "X-Asterisk-VM-Caller-ID-Num:", buf, sizeof(buf))) {
02256 fprintf(text_file_ptr, "<%s>\n", S_OR(buf, ""));
02257 }
02258 if (get_header_by_tag(header_content, "X-Asterisk-VM-Context:", buf, sizeof(buf))) {
02259 fprintf(text_file_ptr, "context=%s\n", S_OR(buf, ""));
02260 }
02261 if (get_header_by_tag(header_content, "X-Asterisk-VM-Orig-time:", buf, sizeof(buf))) {
02262 fprintf(text_file_ptr, "origtime=%s\n", S_OR(buf, ""));
02263 }
02264 if (get_header_by_tag(header_content, "X-Asterisk-VM-Duration:", buf, sizeof(buf))) {
02265 fprintf(text_file_ptr, "duration=%s\n", S_OR(buf, ""));
02266 }
02267 if (get_header_by_tag(header_content, "X-Asterisk-VM-Category:", buf, sizeof(buf))) {
02268 fprintf(text_file_ptr, "category=%s\n", S_OR(buf, ""));
02269 }
02270 if (get_header_by_tag(header_content, "X-Asterisk-VM-Flag:", buf, sizeof(buf))) {
02271 fprintf(text_file_ptr, "flag=%s\n", S_OR(buf, ""));
02272 }
02273 if (get_header_by_tag(header_content, "X-Asterisk-VM-Message-ID:", buf, sizeof(buf))) {
02274 fprintf(text_file_ptr, "msg_id=%s\n", S_OR(buf, ""));
02275 }
02276 fclose(text_file_ptr);
02277
02278 exit:
02279 free_user(vmu);
02280 return res;
02281 }
02282
02283 static int folder_int(const char *folder)
02284 {
02285
02286 if (!folder) {
02287 return 0;
02288 }
02289 if (!strcasecmp(folder, imapfolder)) {
02290 return 0;
02291 } else if (!strcasecmp(folder, "Old")) {
02292 return 1;
02293 } else if (!strcasecmp(folder, "Work")) {
02294 return 2;
02295 } else if (!strcasecmp(folder, "Family")) {
02296 return 3;
02297 } else if (!strcasecmp(folder, "Friends")) {
02298 return 4;
02299 } else if (!strcasecmp(folder, "Cust1")) {
02300 return 5;
02301 } else if (!strcasecmp(folder, "Cust2")) {
02302 return 6;
02303 } else if (!strcasecmp(folder, "Cust3")) {
02304 return 7;
02305 } else if (!strcasecmp(folder, "Cust4")) {
02306 return 8;
02307 } else if (!strcasecmp(folder, "Cust5")) {
02308 return 9;
02309 } else if (!strcasecmp(folder, "Urgent")) {
02310 return 11;
02311 } else {
02312 return 0;
02313 }
02314 }
02315
02316 static int __messagecount(const char *context, const char *mailbox, const char *folder)
02317 {
02318 SEARCHPGM *pgm;
02319 SEARCHHEADER *hdr;
02320
02321 struct ast_vm_user *vmu, vmus;
02322 struct vm_state *vms_p;
02323 int ret = 0;
02324 int fold = folder_int(folder);
02325 int urgent = 0;
02326
02327
02328 if (fold == 11) {
02329 fold = NEW_FOLDER;
02330 urgent = 1;
02331 }
02332
02333 if (ast_strlen_zero(mailbox))
02334 return 0;
02335
02336
02337 vmu = find_user(&vmus, context, mailbox);
02338 if (!vmu) {
02339 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailbox, context);
02340 return -1;
02341 } else {
02342
02343 if (vmu->imapuser[0] == '\0') {
02344 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02345 return -1;
02346 }
02347 }
02348
02349
02350 if (vmu->imapuser[0] == '\0') {
02351 ast_log(AST_LOG_WARNING, "IMAP user not set for mailbox %s\n", vmu->mailbox);
02352 free_user(vmu);
02353 return -1;
02354 }
02355
02356
02357 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
02358 if (!vms_p) {
02359 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
02360 }
02361 if (vms_p) {
02362 ast_debug(3, "Returning before search - user is logged in\n");
02363 if (fold == 0) {
02364 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
02365 }
02366 if (fold == 1) {
02367 return vms_p->oldmessages;
02368 }
02369 }
02370
02371
02372 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
02373 if (!vms_p) {
02374 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
02375 }
02376
02377 if (!vms_p) {
02378 vms_p = create_vm_state_from_user(vmu);
02379 }
02380 ret = init_mailstream(vms_p, fold);
02381 if (!vms_p->mailstream) {
02382 ast_log(AST_LOG_ERROR, "Houston we have a problem - IMAP mailstream is NULL\n");
02383 return -1;
02384 }
02385 if (ret == 0) {
02386 ast_mutex_lock(&vms_p->lock);
02387 pgm = mail_newsearchpgm ();
02388 hdr = mail_newsearchheader ("X-Asterisk-VM-Extension", (char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
02389 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", (char *) S_OR(context, "default"));
02390 pgm->header = hdr;
02391 if (fold != OLD_FOLDER) {
02392 pgm->unseen = 1;
02393 pgm->seen = 0;
02394 }
02395
02396
02397
02398 else {
02399 pgm->unseen = 0;
02400 pgm->seen = 1;
02401 }
02402
02403 if (fold == NEW_FOLDER) {
02404 if (urgent) {
02405 pgm->flagged = 1;
02406 pgm->unflagged = 0;
02407 } else {
02408 pgm->flagged = 0;
02409 pgm->unflagged = 1;
02410 }
02411 }
02412 pgm->undeleted = 1;
02413 pgm->deleted = 0;
02414
02415 vms_p->vmArrayIndex = 0;
02416 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
02417 if (fold == 0 && urgent == 0)
02418 vms_p->newmessages = vms_p->vmArrayIndex;
02419 if (fold == 1)
02420 vms_p->oldmessages = vms_p->vmArrayIndex;
02421 if (fold == 0 && urgent == 1)
02422 vms_p->urgentmessages = vms_p->vmArrayIndex;
02423
02424 mail_free_searchpgm(&pgm);
02425 ast_mutex_unlock(&vms_p->lock);
02426 vms_p->updated = 0;
02427 return vms_p->vmArrayIndex;
02428 } else {
02429 ast_mutex_lock(&vms_p->lock);
02430 mail_ping(vms_p->mailstream);
02431 ast_mutex_unlock(&vms_p->lock);
02432 }
02433 return 0;
02434 }
02435
02436 static int imap_check_limits(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu, int msgnum)
02437 {
02438
02439 check_quota(vms, vmu->imapfolder);
02440 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
02441 ast_debug(1, "*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
02442 if (chan) {
02443 ast_play_and_wait(chan, "vm-mailboxfull");
02444 }
02445 return -1;
02446 }
02447
02448
02449 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));
02450 if (msgnum >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
02451 ast_log(LOG_WARNING, "Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->maxmsg);
02452 if (chan) {
02453 ast_play_and_wait(chan, "vm-mailboxfull");
02454 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
02455 }
02456 return -1;
02457 }
02458
02459 return 0;
02460 }
02461
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471 static int messagecount(const char *context, const char *mailbox, const char *folder)
02472 {
02473 if (ast_strlen_zero(folder) || !strcmp(folder, "INBOX")) {
02474 return __messagecount(context, mailbox, "INBOX") + __messagecount(context, mailbox, "Urgent");
02475 } else {
02476 return __messagecount(context, mailbox, folder);
02477 }
02478 }
02479
02480 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, const char *msg_id)
02481 {
02482 char *myserveremail = serveremail;
02483 char fn[PATH_MAX];
02484 char introfn[PATH_MAX];
02485 char mailbox[256];
02486 char *stringp;
02487 FILE *p = NULL;
02488 char tmp[80] = "/tmp/astmail-XXXXXX";
02489 long len;
02490 void *buf;
02491 int tempcopy = 0;
02492 STRING str;
02493 int ret;
02494 char *imap_flags = NIL;
02495 int msgcount = (messagecount(vmu->context, vmu->mailbox, "INBOX") + messagecount(vmu->context, vmu->mailbox, "Old"));
02496 int box = NEW_FOLDER;
02497
02498
02499 if (msgnum < 0) {
02500 if(!imapgreetings) {
02501 return 0;
02502 } else {
02503 box = GREETINGS_FOLDER;
02504 }
02505 }
02506
02507 if (imap_check_limits(chan, vms, vmu, msgcount)) {
02508 return -1;
02509 }
02510
02511
02512 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
02513 ast_debug(3, "Setting message flag \\\\FLAGGED.\n");
02514 imap_flags = "\\FLAGGED";
02515 }
02516
02517
02518 fmt = ast_strdupa(fmt);
02519 stringp = fmt;
02520 strsep(&stringp, "|");
02521
02522 if (!ast_strlen_zero(vmu->serveremail))
02523 myserveremail = vmu->serveremail;
02524
02525 if (msgnum > -1)
02526 make_file(fn, sizeof(fn), dir, msgnum);
02527 else
02528 ast_copy_string (fn, dir, sizeof(fn));
02529
02530 snprintf(introfn, sizeof(introfn), "%sintro", fn);
02531 if (ast_fileexists(introfn, NULL, NULL) <= 0) {
02532 *introfn = '\0';
02533 }
02534
02535 if (ast_strlen_zero(vmu->email)) {
02536
02537
02538
02539
02540
02541 ast_copy_string(vmu->email, vmu->imapuser, sizeof(vmu->email));
02542 tempcopy = 1;
02543 }
02544
02545 if (!strcmp(fmt, "wav49"))
02546 fmt = "WAV";
02547 ast_debug(3, "Storing file '%s', format '%s'\n", fn, fmt);
02548
02549
02550
02551 if (!(p = vm_mkftemp(tmp))) {
02552 ast_log(AST_LOG_WARNING, "Unable to store '%s' (can't create temporary file)\n", fn);
02553 if (tempcopy)
02554 *(vmu->email) = '\0';
02555 return -1;
02556 }
02557
02558 if (msgnum < 0 && imapgreetings) {
02559 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
02560 ast_log(AST_LOG_WARNING, "Unable to open mailstream.\n");
02561 return -1;
02562 }
02563 imap_delete_old_greeting(fn, vms);
02564 }
02565
02566 make_email_file(p, myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, "INBOX",
02567 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
02568 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
02569 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag, msg_id);
02570
02571 len = ftell(p);
02572 rewind(p);
02573 if (!(buf = ast_malloc(len + 1))) {
02574 ast_log(AST_LOG_ERROR, "Can't allocate %ld bytes to read message\n", len + 1);
02575 fclose(p);
02576 if (tempcopy)
02577 *(vmu->email) = '\0';
02578 return -1;
02579 }
02580 if (fread(buf, len, 1, p) < len) {
02581 if (ferror(p)) {
02582 ast_log(LOG_ERROR, "Short read while reading in mail file.\n");
02583 return -1;
02584 }
02585 }
02586 ((char *) buf)[len] = '\0';
02587 INIT(&str, mail_string, buf, len);
02588 ret = init_mailstream(vms, box);
02589 if (ret == 0) {
02590 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
02591 ast_mutex_lock(&vms->lock);
02592 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
02593 ast_log(LOG_ERROR, "Error while sending the message to %s\n", mailbox);
02594 ast_mutex_unlock(&vms->lock);
02595 fclose(p);
02596 unlink(tmp);
02597 ast_free(buf);
02598 } else {
02599 ast_log(LOG_ERROR, "Could not initialize mailstream for %s\n", mailbox);
02600 fclose(p);
02601 unlink(tmp);
02602 ast_free(buf);
02603 return -1;
02604 }
02605 ast_debug(3, "%s stored\n", fn);
02606
02607 if (tempcopy)
02608 *(vmu->email) = '\0';
02609 inprocess_count(vmu->mailbox, vmu->context, -1);
02610 return 0;
02611
02612 }
02613
02614
02615
02616
02617
02618
02619
02620
02621
02622
02623
02624
02625
02626
02627 static int inboxcount2(const char *mailbox_context, int *urgentmsgs, int *newmsgs, int *oldmsgs)
02628 {
02629 char tmp[PATH_MAX] = "";
02630 char *mailboxnc;
02631 char *context;
02632 char *mb;
02633 char *cur;
02634 if (newmsgs)
02635 *newmsgs = 0;
02636 if (oldmsgs)
02637 *oldmsgs = 0;
02638 if (urgentmsgs)
02639 *urgentmsgs = 0;
02640
02641 ast_debug(3, "Mailbox is set to %s\n", mailbox_context);
02642
02643 if (ast_strlen_zero(mailbox_context))
02644 return 0;
02645
02646 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02647 context = strchr(tmp, '@');
02648 if (strchr(mailbox_context, ',')) {
02649 int tmpnew, tmpold, tmpurgent;
02650 ast_copy_string(tmp, mailbox_context, sizeof(tmp));
02651 mb = tmp;
02652 while ((cur = strsep(&mb, ", "))) {
02653 if (!ast_strlen_zero(cur)) {
02654 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
02655 return -1;
02656 else {
02657 if (newmsgs)
02658 *newmsgs += tmpnew;
02659 if (oldmsgs)
02660 *oldmsgs += tmpold;
02661 if (urgentmsgs)
02662 *urgentmsgs += tmpurgent;
02663 }
02664 }
02665 }
02666 return 0;
02667 }
02668 if (context) {
02669 *context = '\0';
02670 mailboxnc = tmp;
02671 context++;
02672 } else {
02673 context = "default";
02674 mailboxnc = (char *) mailbox_context;
02675 }
02676
02677 if (newmsgs) {
02678 struct ast_vm_user *vmu = find_user(NULL, context, mailboxnc);
02679 if (!vmu) {
02680 ast_log(AST_LOG_ERROR, "Couldn't find mailbox %s in context %s\n", mailboxnc, context);
02681 return -1;
02682 }
02683 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
02684 free_user(vmu);
02685 return -1;
02686 }
02687 free_user(vmu);
02688 }
02689 if (oldmsgs) {
02690 if ((*oldmsgs = __messagecount(context, mailboxnc, "Old")) < 0) {
02691 return -1;
02692 }
02693 }
02694 if (urgentmsgs) {
02695 if ((*urgentmsgs = __messagecount(context, mailboxnc, "Urgent")) < 0) {
02696 return -1;
02697 }
02698 }
02699 return 0;
02700 }
02701
02702
02703
02704
02705
02706
02707
02708
02709
02710
02711
02712 static int has_voicemail(const char *mailbox, const char *folder)
02713 {
02714 char tmp[256], *tmp2, *box, *context;
02715 ast_copy_string(tmp, mailbox, sizeof(tmp));
02716 tmp2 = tmp;
02717 if (strchr(tmp2, ',') || strchr(tmp2, '&')) {
02718 while ((box = strsep(&tmp2, ",&"))) {
02719 if (!ast_strlen_zero(box)) {
02720 if (has_voicemail(box, folder)) {
02721 return 1;
02722 }
02723 }
02724 }
02725 }
02726 if ((context = strchr(tmp, '@'))) {
02727 *context++ = '\0';
02728 } else {
02729 context = "default";
02730 }
02731 return __messagecount(context, tmp, folder) ? 1 : 0;
02732 }
02733
02734
02735
02736
02737
02738
02739
02740
02741
02742
02743
02744
02745
02746
02747
02748
02749 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, const char *dest_folder)
02750 {
02751 struct vm_state *sendvms = NULL;
02752 char messagestring[10];
02753 if (msgnum >= recip->maxmsg) {
02754 ast_log(LOG_WARNING, "Unable to copy mail, mailbox %s is full\n", recip->mailbox);
02755 return -1;
02756 }
02757 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
02758 ast_log(LOG_ERROR, "Couldn't get vm_state for originator's mailbox!!\n");
02759 return -1;
02760 }
02761 if (!get_vm_state_by_imapuser(recip->imapuser, 0)) {
02762 ast_log(LOG_ERROR, "Couldn't get vm_state for destination mailbox!\n");
02763 return -1;
02764 }
02765 snprintf(messagestring, sizeof(messagestring), "%ld", sendvms->msgArray[msgnum]);
02766 ast_mutex_lock(&sendvms->lock);
02767 if ((mail_copy(sendvms->mailstream, messagestring, (char *) mbox(vmu, imbox)) == T)) {
02768 ast_mutex_unlock(&sendvms->lock);
02769 return 0;
02770 }
02771 ast_mutex_unlock(&sendvms->lock);
02772 ast_log(LOG_WARNING, "Unable to copy message from mailbox %s to mailbox %s\n", vmu->mailbox, recip->mailbox);
02773 return -1;
02774 }
02775
02776 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int use_folder)
02777 {
02778 char tmp[256], *t = tmp;
02779 size_t left = sizeof(tmp);
02780
02781 if (box == OLD_FOLDER) {
02782 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER), sizeof(vms->curbox));
02783 } else {
02784 ast_copy_string(vms->curbox, mbox(NULL, box), sizeof(vms->curbox));
02785 }
02786
02787 if (box == NEW_FOLDER) {
02788 ast_copy_string(vms->vmbox, "vm-INBOX", sizeof(vms->vmbox));
02789 } else {
02790 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", mbox(NULL, box));
02791 }
02792
02793
02794 ast_build_string(&t, &left, "{%s:%s/imap", S_OR(vms->imapserver, imapserver), S_OR(vms->imapport, imapport));
02795
02796
02797 if (!ast_strlen_zero(authuser))
02798 ast_build_string(&t, &left, "/authuser=%s", authuser);
02799
02800
02801 if (!ast_strlen_zero(imapflags) || !(ast_strlen_zero(vms->imapflags))) {
02802 ast_build_string(&t, &left, "/%s", S_OR(vms->imapflags, imapflags));
02803 }
02804
02805
02806 #if 1
02807 ast_build_string(&t, &left, "/user=%s}", vms->imapuser);
02808 #else
02809 ast_build_string(&t, &left, "/user=%s/novalidate-cert}", vms->imapuser);
02810 #endif
02811 if (box == NEW_FOLDER || box == OLD_FOLDER)
02812 snprintf(spec, len, "%s%s", tmp, use_folder? vms->imapfolder: "INBOX");
02813 else if (box == GREETINGS_FOLDER)
02814 snprintf(spec, len, "%s%s", tmp, greetingfolder);
02815 else {
02816 if (!ast_strlen_zero(imapparentfolder)) {
02817
02818 snprintf(spec, len, "%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
02819 } else {
02820 snprintf(spec, len, "%s%s", tmp, mbox(NULL, box));
02821 }
02822 }
02823 }
02824
02825 static int init_mailstream(struct vm_state *vms, int box)
02826 {
02827 MAILSTREAM *stream = NIL;
02828 long debug;
02829 char tmp[256];
02830
02831 if (!vms) {
02832 ast_log(LOG_ERROR, "vm_state is NULL!\n");
02833 return -1;
02834 }
02835 ast_debug(3, "vm_state user is:%s\n", vms->imapuser);
02836 if (vms->mailstream == NIL || !vms->mailstream) {
02837 ast_debug(1, "mailstream not set.\n");
02838 } else {
02839 stream = vms->mailstream;
02840 }
02841
02842 debug = NIL;
02843
02844 if (delimiter == '\0') {
02845 char *cp;
02846 #ifdef USE_SYSTEM_IMAP
02847 #include <imap/linkage.c>
02848 #elif defined(USE_SYSTEM_CCLIENT)
02849 #include <c-client/linkage.c>
02850 #else
02851 #include "linkage.c"
02852 #endif
02853
02854 imap_mailbox_name(tmp, sizeof(tmp), vms, 0, 1);
02855 ast_mutex_lock(&vms->lock);
02856 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02857 ast_mutex_unlock(&vms->lock);
02858 if (stream == NIL) {
02859 ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
02860 return -1;
02861 }
02862 get_mailbox_delimiter(vms, stream);
02863
02864 for (cp = vms->imapfolder; *cp; cp++)
02865 if (*cp == '/')
02866 *cp = delimiter;
02867 }
02868
02869 imap_mailbox_name(tmp, sizeof(tmp), vms, box, 1);
02870 ast_debug(3, "Before mail_open, server: %s, box:%d\n", tmp, box);
02871 ast_mutex_lock(&vms->lock);
02872 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
02873 ast_mutex_unlock(&vms->lock);
02874 if (vms->mailstream == NIL) {
02875 return -1;
02876 } else {
02877 return 0;
02878 }
02879 }
02880
02881 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
02882 {
02883 SEARCHPGM *pgm;
02884 SEARCHHEADER *hdr;
02885 int urgent = 0;
02886
02887
02888 if (box == 11) {
02889 box = NEW_FOLDER;
02890 urgent = 1;
02891 }
02892
02893 ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
02894 ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
02895 ast_copy_string(vms->imapserver, vmu->imapserver, sizeof(vms->imapserver));
02896 ast_copy_string(vms->imapport, vmu->imapport, sizeof(vms->imapport));
02897 ast_copy_string(vms->imapflags, vmu->imapflags, sizeof(vms->imapflags));
02898 vms->imapversion = vmu->imapversion;
02899 ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
02900
02901 if (init_mailstream(vms, box) || !vms->mailstream) {
02902 ast_log(AST_LOG_ERROR, "Could not initialize mailstream\n");
02903 return -1;
02904 }
02905
02906 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
02907
02908
02909 if (box == 0) {
02910 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
02911 check_quota(vms, (char *) mbox(vmu, box));
02912 }
02913
02914 ast_mutex_lock(&vms->lock);
02915 pgm = mail_newsearchpgm();
02916
02917
02918 hdr = mail_newsearchheader("X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->mailbox));
02919 hdr->next = mail_newsearchheader("X-Asterisk-VM-Context", vmu->context);
02920 pgm->header = hdr;
02921 pgm->deleted = 0;
02922 pgm->undeleted = 1;
02923
02924
02925 if (box == NEW_FOLDER && urgent == 1) {
02926 pgm->unseen = 1;
02927 pgm->seen = 0;
02928 pgm->flagged = 1;
02929 pgm->unflagged = 0;
02930 } else if (box == NEW_FOLDER && urgent == 0) {
02931 pgm->unseen = 1;
02932 pgm->seen = 0;
02933 pgm->flagged = 0;
02934 pgm->unflagged = 1;
02935 } else if (box == OLD_FOLDER) {
02936 pgm->seen = 1;
02937 pgm->unseen = 0;
02938 }
02939
02940 ast_debug(3, "Before mail_search_full, user is %s\n", vmu->imapuser);
02941
02942 vms->vmArrayIndex = 0;
02943 mail_search_full (vms->mailstream, NULL, pgm, NIL);
02944 vms->lastmsg = vms->vmArrayIndex - 1;
02945 mail_free_searchpgm(&pgm);
02946
02947
02948
02949
02950 if (box == 0 && !vms->dh_arraysize) {
02951 ast_log(LOG_WARNING, "The code expects the old messages to be checked first, fix the code.\n");
02952 }
02953 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
02954 ast_mutex_unlock(&vms->lock);
02955 return -1;
02956 }
02957
02958 ast_mutex_unlock(&vms->lock);
02959 return 0;
02960 }
02961
02962 static void write_file(char *filename, char *buffer, unsigned long len)
02963 {
02964 FILE *output;
02965
02966 output = fopen (filename, "w");
02967 if (fwrite(buffer, len, 1, output) != 1) {
02968 if (ferror(output)) {
02969 ast_log(LOG_ERROR, "Short write while writing e-mail body: %s.\n", strerror(errno));
02970 }
02971 }
02972 fclose (output);
02973 }
02974
02975 static void update_messages_by_imapuser(const char *user, unsigned long number)
02976 {
02977 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
02978
02979 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
02980 return;
02981 }
02982
02983 ast_debug(3, "saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
02984 vms->msgArray[vms->vmArrayIndex++] = number;
02985 }
02986
02987 void mm_searched(MAILSTREAM *stream, unsigned long number)
02988 {
02989 char *mailbox = stream->mailbox, buf[1024] = "", *user;
02990
02991 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))))
02992 return;
02993
02994 update_messages_by_imapuser(user, number);
02995 }
02996
02997 static struct ast_vm_user *find_user_realtime_imapuser(const char *imapuser)
02998 {
02999 struct ast_variable *var;
03000 struct ast_vm_user *vmu;
03001
03002 vmu = ast_calloc(1, sizeof *vmu);
03003 if (!vmu)
03004 return NULL;
03005
03006 populate_defaults(vmu);
03007 ast_set_flag(vmu, VM_ALLOCED);
03008
03009 var = ast_load_realtime("voicemail", "imapuser", imapuser, NULL);
03010 if (var) {
03011 apply_options_full(vmu, var);
03012 ast_variables_destroy(var);
03013 return vmu;
03014 } else {
03015 ast_free(vmu);
03016 return NULL;
03017 }
03018 }
03019
03020
03021
03022 void mm_exists(MAILSTREAM * stream, unsigned long number)
03023 {
03024
03025 ast_debug(4, "Entering EXISTS callback for message %ld\n", number);
03026 if (number == 0) return;
03027 set_update(stream);
03028 }
03029
03030
03031 void mm_expunged(MAILSTREAM * stream, unsigned long number)
03032 {
03033
03034 ast_debug(4, "Entering EXPUNGE callback for message %ld\n", number);
03035 if (number == 0) return;
03036 set_update(stream);
03037 }
03038
03039
03040 void mm_flags(MAILSTREAM * stream, unsigned long number)
03041 {
03042
03043 ast_debug(4, "Entering FLAGS callback for message %ld\n", number);
03044 if (number == 0) return;
03045 set_update(stream);
03046 }
03047
03048
03049 void mm_notify(MAILSTREAM * stream, char *string, long errflg)
03050 {
03051 ast_debug(5, "Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg, string);
03052 mm_log (string, errflg);
03053 }
03054
03055
03056 void mm_list(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
03057 {
03058 if (delimiter == '\0') {
03059 delimiter = delim;
03060 }
03061
03062 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
03063 if (attributes & LATT_NOINFERIORS)
03064 ast_debug(5, "no inferiors\n");
03065 if (attributes & LATT_NOSELECT)
03066 ast_debug(5, "no select\n");
03067 if (attributes & LATT_MARKED)
03068 ast_debug(5, "marked\n");
03069 if (attributes & LATT_UNMARKED)
03070 ast_debug(5, "unmarked\n");
03071 }
03072
03073
03074 void mm_lsub(MAILSTREAM * stream, int delim, char *mailbox, long attributes)
03075 {
03076 ast_debug(5, "Delimiter set to %c and mailbox %s\n", delim, mailbox);
03077 if (attributes & LATT_NOINFERIORS)
03078 ast_debug(5, "no inferiors\n");
03079 if (attributes & LATT_NOSELECT)
03080 ast_debug(5, "no select\n");
03081 if (attributes & LATT_MARKED)
03082 ast_debug(5, "marked\n");
03083 if (attributes & LATT_UNMARKED)
03084 ast_debug(5, "unmarked\n");
03085 }
03086
03087
03088 void mm_status(MAILSTREAM * stream, char *mailbox, MAILSTATUS * status)
03089 {
03090 ast_log(AST_LOG_NOTICE, " Mailbox %s", mailbox);
03091 if (status->flags & SA_MESSAGES)
03092 ast_log(AST_LOG_NOTICE, ", %lu messages", status->messages);
03093 if (status->flags & SA_RECENT)
03094 ast_log(AST_LOG_NOTICE, ", %lu recent", status->recent);
03095 if (status->flags & SA_UNSEEN)
03096 ast_log(AST_LOG_NOTICE, ", %lu unseen", status->unseen);
03097 if (status->flags & SA_UIDVALIDITY)
03098 ast_log(AST_LOG_NOTICE, ", %lu UID validity", status->uidvalidity);
03099 if (status->flags & SA_UIDNEXT)
03100 ast_log(AST_LOG_NOTICE, ", %lu next UID", status->uidnext);
03101 ast_log(AST_LOG_NOTICE, "\n");
03102 }
03103
03104
03105 void mm_log(char *string, long errflg)
03106 {
03107 switch ((short) errflg) {
03108 case NIL:
03109 ast_debug(1, "IMAP Info: %s\n", string);
03110 break;
03111 case PARSE:
03112 case WARN:
03113 ast_log(AST_LOG_WARNING, "IMAP Warning: %s\n", string);
03114 break;
03115 case ERROR:
03116 ast_log(AST_LOG_ERROR, "IMAP Error: %s\n", string);
03117 break;
03118 }
03119 }
03120
03121
03122 void mm_dlog(char *string)
03123 {
03124 ast_log(AST_LOG_NOTICE, "%s\n", string);
03125 }
03126
03127
03128 void mm_login(NETMBX * mb, char *user, char *pwd, long trial)
03129 {
03130 struct ast_vm_user *vmu;
03131
03132 ast_debug(4, "Entering callback mm_login\n");
03133
03134 ast_copy_string(user, mb->user, MAILTMPLEN);
03135
03136
03137 if (!ast_strlen_zero(authpassword)) {
03138 ast_copy_string(pwd, authpassword, MAILTMPLEN);
03139 } else {
03140 AST_LIST_TRAVERSE(&users, vmu, list) {
03141 if (!strcasecmp(mb->user, vmu->imapuser)) {
03142 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
03143 break;
03144 }
03145 }
03146 if (!vmu) {
03147 if ((vmu = find_user_realtime_imapuser(mb->user))) {
03148 ast_copy_string(pwd, vmu->imappassword, MAILTMPLEN);
03149 free_user(vmu);
03150 }
03151 }
03152 }
03153 }
03154
03155
03156 void mm_critical(MAILSTREAM * stream)
03157 {
03158 }
03159
03160
03161 void mm_nocritical(MAILSTREAM * stream)
03162 {
03163 }
03164
03165
03166 long mm_diskerror(MAILSTREAM * stream, long errcode, long serious)
03167 {
03168 kill (getpid (), SIGSTOP);
03169 return NIL;
03170 }
03171
03172
03173 void mm_fatal(char *string)
03174 {
03175 ast_log(AST_LOG_ERROR, "IMAP access FATAL error: %s\n", string);
03176 }
03177
03178
03179 static void mm_parsequota(MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota)
03180 {
03181 struct vm_state *vms;
03182 char *mailbox = stream->mailbox, *user;
03183 char buf[1024] = "";
03184 unsigned long usage = 0, limit = 0;
03185
03186 while (pquota) {
03187 usage = pquota->usage;
03188 limit = pquota->limit;
03189 pquota = pquota->next;
03190 }
03191
03192 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)))) {
03193 ast_log(AST_LOG_ERROR, "No state found.\n");
03194 return;
03195 }
03196
03197 ast_debug(3, "User %s usage is %lu, limit is %lu\n", user, usage, limit);
03198
03199 vms->quota_usage = usage;
03200 vms->quota_limit = limit;
03201 }
03202
03203 static char *get_header_by_tag(char *header, char *tag, char *buf, size_t len)
03204 {
03205 char *start, *eol_pnt;
03206 int taglen;
03207
03208 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
03209 return NULL;
03210
03211 taglen = strlen(tag) + 1;
03212 if (taglen < 1)
03213 return NULL;
03214
03215 if (!(start = strstr(header, tag)))
03216 return NULL;
03217
03218
03219 memset(buf, 0, len);
03220
03221 ast_copy_string(buf, start+taglen, len);
03222 if ((eol_pnt = strchr(buf,'\r')) || (eol_pnt = strchr(buf,'\n')))
03223 *eol_pnt = '\0';
03224 return buf;
03225 }
03226
03227 static char *get_user_by_mailbox(char *mailbox, char *buf, size_t len)
03228 {
03229 char *start, *eol_pnt, *quote;
03230
03231 if (ast_strlen_zero(mailbox))
03232 return NULL;
03233
03234 if (!(start = strstr(mailbox, "/user=")))
03235 return NULL;
03236
03237 ast_copy_string(buf, start+6, len);
03238
03239 if (!(quote = strchr(buf, '"'))) {
03240 if ((eol_pnt = strchr(buf, '/')) || (eol_pnt = strchr(buf, '}'))) {
03241 *eol_pnt = '\0';
03242 }
03243 return buf;
03244 } else {
03245 if ((eol_pnt = strchr(quote + 1, '"'))) {
03246 *eol_pnt = '\0';
03247 }
03248 return quote + 1;
03249 }
03250 }
03251
03252 static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
03253 {
03254 struct vm_state *vms_p;
03255
03256 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03257 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->mailbox)) {
03258 return vms_p;
03259 }
03260 ast_debug(5, "Adding new vmstate for %s\n", vmu->imapuser);
03261 if (!(vms_p = ast_calloc(1, sizeof(*vms_p))))
03262 return NULL;
03263 ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
03264 ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
03265 ast_copy_string(vms_p->imapserver, vmu->imapserver, sizeof(vms_p->imapserver));
03266 ast_copy_string(vms_p->imapport, vmu->imapport, sizeof(vms_p->imapport));
03267 ast_copy_string(vms_p->imapflags, vmu->imapflags, sizeof(vms_p->imapflags));
03268 ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username));
03269 ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
03270 vms_p->mailstream = NIL;
03271 vms_p->imapversion = vmu->imapversion;
03272 ast_debug(5, "Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
03273 vms_p->updated = 1;
03274
03275 ast_copy_string(vms_p->curbox, mbox(vmu, 0), sizeof(vms_p->curbox));
03276 init_vm_state(vms_p);
03277 vmstate_insert(vms_p);
03278 return vms_p;
03279 }
03280
03281 static struct vm_state *get_vm_state_by_imapuser(const char *user, int interactive)
03282 {
03283 struct vmstate *vlist = NULL;
03284
03285 if (interactive) {
03286 struct vm_state *vms;
03287 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03288 vms = pthread_getspecific(ts_vmstate.key);
03289 return vms;
03290 }
03291
03292 AST_LIST_LOCK(&vmstates);
03293 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03294 if (!vlist->vms) {
03295 ast_debug(3, "error: vms is NULL for %s\n", user);
03296 continue;
03297 }
03298 if (vlist->vms->imapversion != imapversion) {
03299 continue;
03300 }
03301 if (!vlist->vms->imapuser) {
03302 ast_debug(3, "error: imapuser is NULL for %s\n", user);
03303 continue;
03304 }
03305
03306 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
03307 AST_LIST_UNLOCK(&vmstates);
03308 return vlist->vms;
03309 }
03310 }
03311 AST_LIST_UNLOCK(&vmstates);
03312
03313 ast_debug(3, "%s not found in vmstates\n", user);
03314
03315 return NULL;
03316 }
03317
03318 static struct vm_state *get_vm_state_by_mailbox(const char *mailbox, const char *context, int interactive)
03319 {
03320
03321 struct vmstate *vlist = NULL;
03322 const char *local_context = S_OR(context, "default");
03323
03324 if (interactive) {
03325 struct vm_state *vms;
03326 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
03327 vms = pthread_getspecific(ts_vmstate.key);
03328 return vms;
03329 }
03330
03331 AST_LIST_LOCK(&vmstates);
03332 AST_LIST_TRAVERSE(&vmstates, vlist, list) {
03333 if (!vlist->vms) {
03334 ast_debug(3, "error: vms is NULL for %s\n", mailbox);
03335 continue;
03336 }
03337 if (vlist->vms->imapversion != imapversion) {
03338 continue;
03339 }
03340 if (!vlist->vms->username || !vlist->vms->context) {
03341 ast_debug(3, "error: username is NULL for %s\n", mailbox);
03342 continue;
03343 }
03344
03345 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);
03346
03347 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
03348 ast_debug(3, "Found it!\n");
03349 AST_LIST_UNLOCK(&vmstates);
03350 return vlist->vms;
03351 }
03352 }
03353 AST_LIST_UNLOCK(&vmstates);
03354
03355 ast_debug(3, "%s not found in vmstates\n", mailbox);
03356
03357 return NULL;
03358 }
03359
03360 static void vmstate_insert(struct vm_state *vms)
03361 {
03362 struct vmstate *v;
03363 struct vm_state *altvms;
03364
03365
03366
03367
03368 if (vms->interactive == 1) {
03369 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
03370 if (altvms) {
03371 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03372 vms->newmessages = altvms->newmessages;
03373 vms->oldmessages = altvms->oldmessages;
03374 vms->vmArrayIndex = altvms->vmArrayIndex;
03375 vms->lastmsg = altvms->lastmsg;
03376 vms->curmsg = altvms->curmsg;
03377
03378 vms->persist_vms = altvms;
03379
03380 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
03381 vms->mailstream = altvms->mailstream;
03382 #else
03383 vms->mailstream = NIL;
03384 #endif
03385 }
03386 return;
03387 }
03388
03389 if (!(v = ast_calloc(1, sizeof(*v))))
03390 return;
03391
03392 v->vms = vms;
03393
03394 ast_debug(3, "Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03395
03396 AST_LIST_LOCK(&vmstates);
03397 AST_LIST_INSERT_TAIL(&vmstates, v, list);
03398 AST_LIST_UNLOCK(&vmstates);
03399 }
03400
03401 static void vmstate_delete(struct vm_state *vms)
03402 {
03403 struct vmstate *vc = NULL;
03404 struct vm_state *altvms = NULL;
03405
03406
03407
03408 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
03409 ast_debug(3, "Duplicate mailbox %s, copying message info...\n", vms->username);
03410 altvms->newmessages = vms->newmessages;
03411 altvms->oldmessages = vms->oldmessages;
03412 altvms->updated = 1;
03413 vms->mailstream = mail_close(vms->mailstream);
03414
03415
03416 return;
03417 }
03418
03419 ast_debug(3, "Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03420
03421 AST_LIST_LOCK(&vmstates);
03422 AST_LIST_TRAVERSE_SAFE_BEGIN(&vmstates, vc, list) {
03423 if (vc->vms == vms) {
03424 AST_LIST_REMOVE_CURRENT(list);
03425 break;
03426 }
03427 }
03428 AST_LIST_TRAVERSE_SAFE_END
03429 AST_LIST_UNLOCK(&vmstates);
03430
03431 if (vc) {
03432 ast_mutex_destroy(&vc->vms->lock);
03433 ast_free(vc);
03434 }
03435 else
03436 ast_log(AST_LOG_ERROR, "No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
03437 }
03438
03439 static void set_update(MAILSTREAM * stream)
03440 {
03441 struct vm_state *vms;
03442 char *mailbox = stream->mailbox, *user;
03443 char buf[1024] = "";
03444
03445 if (!(user = get_user_by_mailbox(mailbox, buf, sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
03446 if (user && option_debug > 2)
03447 ast_log(AST_LOG_WARNING, "User %s mailbox not found for update.\n", user);
03448 return;
03449 }
03450
03451 ast_debug(3, "User %s mailbox set for update.\n", user);
03452
03453 vms->updated = 1;
03454 }
03455
03456 static void init_vm_state(struct vm_state *vms)
03457 {
03458 int x;
03459 vms->vmArrayIndex = 0;
03460 for (x = 0; x < VMSTATE_MAX_MSG_ARRAY; x++) {
03461 vms->msgArray[x] = 0;
03462 }
03463 ast_mutex_init(&vms->lock);
03464 }
03465
03466 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro)
03467 {
03468 char *body_content;
03469 char *body_decoded;
03470 char *fn = is_intro ? vms->introfn : vms->fn;
03471 unsigned long len;
03472 unsigned long newlen;
03473 char filename[256];
03474
03475 if (!body || body == NIL)
03476 return -1;
03477
03478 ast_mutex_lock(&vms->lock);
03479 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
03480 ast_mutex_unlock(&vms->lock);
03481 if (body_content != NIL) {
03482 snprintf(filename, sizeof(filename), "%s.%s", fn, format);
03483
03484 body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
03485
03486 if (!newlen) {
03487 return -1;
03488 }
03489 write_file(filename, (char *) body_decoded, newlen);
03490 } else {
03491 ast_debug(5, "Body of message is NULL.\n");
03492 return -1;
03493 }
03494 return 0;
03495 }
03496
03497
03498
03499
03500
03501
03502
03503
03504
03505 static void get_mailbox_delimiter(struct vm_state *vms, MAILSTREAM *stream) {
03506 char tmp[50];
03507 snprintf(tmp, sizeof(tmp), "{%s}", S_OR(vms->imapserver, imapserver));
03508 mail_list(stream, tmp, "*");
03509 }
03510
03511
03512
03513
03514
03515
03516
03517
03518 static void check_quota(struct vm_state *vms, char *mailbox) {
03519 ast_mutex_lock(&vms->lock);
03520 mail_parameters(NULL, SET_QUOTA, (void *) mm_parsequota);
03521 ast_debug(3, "Mailbox name set to: %s, about to check quotas\n", mailbox);
03522 if (vms && vms->mailstream != NULL) {
03523 imap_getquotaroot(vms->mailstream, mailbox);
03524 } else {
03525 ast_log(AST_LOG_WARNING, "Mailstream not available for mailbox: %s\n", mailbox);
03526 }
03527 ast_mutex_unlock(&vms->lock);
03528 }
03529
03530 #endif
03531
03532
03533
03534
03535
03536 static int vm_lock_path(const char *path)
03537 {
03538 switch (ast_lock_path(path)) {
03539 case AST_LOCK_TIMEOUT:
03540 return -1;
03541 default:
03542 return 0;
03543 }
03544 }
03545
03546 #define MSG_ID_LEN 256
03547
03548
03549 static int msg_id_incrementor;
03550
03551
03552
03553
03554
03555 static void generate_msg_id(char *dst);
03556
03557 #ifdef ODBC_STORAGE
03558 struct generic_prepare_struct {
03559 char *sql;
03560 int argc;
03561 char **argv;
03562 };
03563
03564 static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
03565 {
03566 struct generic_prepare_struct *gps = data;
03567 int res, i;
03568 SQLHSTMT stmt;
03569
03570 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
03571 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03572 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
03573 return NULL;
03574 }
03575 res = SQLPrepare(stmt, (unsigned char *) gps->sql, SQL_NTS);
03576 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03577 ast_log(AST_LOG_WARNING, "SQL Prepare failed![%s]\n", gps->sql);
03578 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03579 return NULL;
03580 }
03581 for (i = 0; i < gps->argc; i++)
03582 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
03583
03584 return stmt;
03585 }
03586
03587 static void odbc_update_msg_id(char *dir, int msg_num, char *msg_id)
03588 {
03589 SQLHSTMT stmt;
03590 char sql[PATH_MAX];
03591 struct odbc_obj *obj;
03592 char msg_num_str[20];
03593 char *argv[] = { msg_id, dir, msg_num_str };
03594 struct generic_prepare_struct gps = { .sql = sql, .argc = 3, .argv = argv };
03595
03596 obj = ast_odbc_request_obj(odbc_database, 0);
03597 if (!obj) {
03598 ast_log(LOG_WARNING, "Unable to update message ID for message %d in %s\n", msg_num, dir);
03599 return;
03600 }
03601
03602 snprintf(msg_num_str, sizeof(msg_num_str), "%d", msg_num);
03603 snprintf(sql, sizeof(sql), "UPDATE %s SET msg_id=? WHERE dir=? AND msgnum=?", odbc_table);
03604 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03605 if (!stmt) {
03606 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03607 } else {
03608 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03609 }
03610 ast_odbc_release_obj(obj);
03611 return;
03612 }
03613
03614
03615
03616
03617
03618
03619
03620
03621
03622
03623
03624
03625
03626
03627
03628 static int retrieve_file(char *dir, int msgnum)
03629 {
03630 int x = 0;
03631 int res;
03632 int fd = -1;
03633 size_t fdlen = 0;
03634 void *fdm = MAP_FAILED;
03635 SQLSMALLINT colcount = 0;
03636 SQLHSTMT stmt;
03637 char sql[PATH_MAX];
03638 char fmt[80]="";
03639 char *c;
03640 char coltitle[256];
03641 SQLSMALLINT collen;
03642 SQLSMALLINT datatype;
03643 SQLSMALLINT decimaldigits;
03644 SQLSMALLINT nullable;
03645 SQLULEN colsize;
03646 SQLLEN colsize2;
03647 FILE *f = NULL;
03648 char rowdata[80];
03649 char fn[PATH_MAX];
03650 char full_fn[PATH_MAX];
03651 char msgnums[80];
03652 char *argv[] = { dir, msgnums };
03653 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03654
03655 struct odbc_obj *obj;
03656 obj = ast_odbc_request_obj(odbc_database, 0);
03657 if (obj) {
03658 ast_copy_string(fmt, vmfmts, sizeof(fmt));
03659 c = strchr(fmt, '|');
03660 if (c)
03661 *c = '\0';
03662 if (!strcasecmp(fmt, "wav49"))
03663 strcpy(fmt, "WAV");
03664 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03665 if (msgnum > -1)
03666 make_file(fn, sizeof(fn), dir, msgnum);
03667 else
03668 ast_copy_string(fn, dir, sizeof(fn));
03669
03670
03671 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
03672
03673 if (!(f = fopen(full_fn, "w+"))) {
03674 ast_log(AST_LOG_WARNING, "Failed to open/create '%s'\n", full_fn);
03675 goto yuck;
03676 }
03677
03678 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
03679 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03680 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03681 if (!stmt) {
03682 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03683 ast_odbc_release_obj(obj);
03684 goto yuck;
03685 }
03686 res = SQLFetch(stmt);
03687 if (res == SQL_NO_DATA) {
03688 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03689 ast_odbc_release_obj(obj);
03690 goto yuck;
03691 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03692 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03693 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03694 ast_odbc_release_obj(obj);
03695 goto yuck;
03696 }
03697 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
03698 if (fd < 0) {
03699 ast_log(AST_LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
03700 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03701 ast_odbc_release_obj(obj);
03702 goto yuck;
03703 }
03704 res = SQLNumResultCols(stmt, &colcount);
03705 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03706 ast_log(AST_LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
03707 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03708 ast_odbc_release_obj(obj);
03709 goto yuck;
03710 }
03711 if (f)
03712 fprintf(f, "[message]\n");
03713 for (x = 0; x < colcount; x++) {
03714 rowdata[0] = '\0';
03715 colsize = 0;
03716 collen = sizeof(coltitle);
03717 res = SQLDescribeCol(stmt, x + 1, (unsigned char *) coltitle, sizeof(coltitle), &collen,
03718 &datatype, &colsize, &decimaldigits, &nullable);
03719 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03720 ast_log(AST_LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
03721 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03722 ast_odbc_release_obj(obj);
03723 goto yuck;
03724 }
03725 if (!strcasecmp(coltitle, "recording")) {
03726 off_t offset;
03727 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
03728 fdlen = colsize2;
03729 if (fd > -1) {
03730 char tmp[1]="";
03731 lseek(fd, fdlen - 1, SEEK_SET);
03732 if (write(fd, tmp, 1) != 1) {
03733 close(fd);
03734 fd = -1;
03735 continue;
03736 }
03737
03738 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
03739 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
03740 ast_log(AST_LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
03741 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03742 ast_odbc_release_obj(obj);
03743 goto yuck;
03744 } else {
03745 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
03746 munmap(fdm, CHUNKSIZE);
03747 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03748 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03749 unlink(full_fn);
03750 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
03751 ast_odbc_release_obj(obj);
03752 goto yuck;
03753 }
03754 }
03755 }
03756 if (truncate(full_fn, fdlen) < 0) {
03757 ast_log(LOG_WARNING, "Unable to truncate '%s': %s\n", full_fn, strerror(errno));
03758 }
03759 }
03760 } else {
03761 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03762 if ((res == SQL_NULL_DATA) && (!strcasecmp(coltitle, "msg_id"))) {
03763 char msg_id[MSG_ID_LEN];
03764 generate_msg_id(msg_id);
03765 snprintf(rowdata, sizeof(rowdata), "%s", msg_id);
03766 odbc_update_msg_id(dir, msgnum, msg_id);
03767 } else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03768 ast_log(AST_LOG_WARNING, "SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
03769 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03770 ast_odbc_release_obj(obj);
03771 goto yuck;
03772 }
03773 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
03774 fprintf(f, "%s=%s\n", coltitle, rowdata);
03775 }
03776 }
03777 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03778 ast_odbc_release_obj(obj);
03779 } else
03780 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03781 yuck:
03782 if (f)
03783 fclose(f);
03784 if (fd > -1)
03785 close(fd);
03786 return x - 1;
03787 }
03788
03789
03790
03791
03792
03793
03794
03795
03796
03797
03798
03799
03800 static int last_message_index(struct ast_vm_user *vmu, char *dir)
03801 {
03802 int x = 0;
03803 int res;
03804 SQLHSTMT stmt;
03805 char sql[PATH_MAX];
03806 char rowdata[20];
03807 char *argv[] = { dir };
03808 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03809
03810 struct odbc_obj *obj;
03811 obj = ast_odbc_request_obj(odbc_database, 0);
03812 if (obj) {
03813 snprintf(sql, sizeof(sql), "SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
03814
03815 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03816 if (!stmt) {
03817 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03818 ast_odbc_release_obj(obj);
03819 goto yuck;
03820 }
03821 res = SQLFetch(stmt);
03822 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03823 if (res == SQL_NO_DATA) {
03824 ast_log(AST_LOG_DEBUG, "Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
03825 } else {
03826 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03827 }
03828
03829 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03830 ast_odbc_release_obj(obj);
03831 goto yuck;
03832 }
03833 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03834 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03835 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03836 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03837 ast_odbc_release_obj(obj);
03838 goto yuck;
03839 }
03840 if (sscanf(rowdata, "%30d", &x) != 1)
03841 ast_log(AST_LOG_WARNING, "Failed to read message index!\n");
03842 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03843 ast_odbc_release_obj(obj);
03844 return x;
03845 } else
03846 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03847 yuck:
03848 return x - 1;
03849 }
03850
03851
03852
03853
03854
03855
03856
03857
03858
03859
03860 static int message_exists(char *dir, int msgnum)
03861 {
03862 int x = 0;
03863 int res;
03864 SQLHSTMT stmt;
03865 char sql[PATH_MAX];
03866 char rowdata[20];
03867 char msgnums[20];
03868 char *argv[] = { dir, msgnums };
03869 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03870
03871 struct odbc_obj *obj;
03872 obj = ast_odbc_request_obj(odbc_database, 0);
03873 if (obj) {
03874 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
03875 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03876 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03877 if (!stmt) {
03878 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03879 ast_odbc_release_obj(obj);
03880 goto yuck;
03881 }
03882 res = SQLFetch(stmt);
03883 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03884 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03885 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03886 ast_odbc_release_obj(obj);
03887 goto yuck;
03888 }
03889 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03890 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03891 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03892 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03893 ast_odbc_release_obj(obj);
03894 goto yuck;
03895 }
03896 if (sscanf(rowdata, "%30d", &x) != 1)
03897 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03898 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03899 ast_odbc_release_obj(obj);
03900 } else
03901 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03902 yuck:
03903 return x;
03904 }
03905
03906
03907
03908
03909
03910
03911
03912
03913
03914
03915 static int count_messages(struct ast_vm_user *vmu, char *dir)
03916 {
03917 int x = 0;
03918 int res;
03919 SQLHSTMT stmt;
03920 char sql[PATH_MAX];
03921 char rowdata[20];
03922 char *argv[] = { dir };
03923 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
03924
03925 struct odbc_obj *obj;
03926 obj = ast_odbc_request_obj(odbc_database, 0);
03927 if (obj) {
03928 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
03929 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03930 if (!stmt) {
03931 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03932 ast_odbc_release_obj(obj);
03933 goto yuck;
03934 }
03935 res = SQLFetch(stmt);
03936 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03937 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
03938 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03939 ast_odbc_release_obj(obj);
03940 goto yuck;
03941 }
03942 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
03943 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
03944 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
03945 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03946 ast_odbc_release_obj(obj);
03947 goto yuck;
03948 }
03949 if (sscanf(rowdata, "%30d", &x) != 1)
03950 ast_log(AST_LOG_WARNING, "Failed to read message count!\n");
03951 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03952 ast_odbc_release_obj(obj);
03953 return x;
03954 } else
03955 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03956 yuck:
03957 return x - 1;
03958
03959 }
03960
03961
03962
03963
03964
03965
03966
03967
03968
03969
03970
03971 static void delete_file(const char *sdir, int smsg)
03972 {
03973 SQLHSTMT stmt;
03974 char sql[PATH_MAX];
03975 char msgnums[20];
03976 char *argv[] = { NULL, msgnums };
03977 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
03978 struct odbc_obj *obj;
03979
03980 argv[0] = ast_strdupa(sdir);
03981
03982 obj = ast_odbc_request_obj(odbc_database, 0);
03983 if (obj) {
03984 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
03985 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
03986 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
03987 if (!stmt)
03988 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
03989 else
03990 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
03991 ast_odbc_release_obj(obj);
03992 } else
03993 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
03994 return;
03995 }
03996
03997
03998
03999
04000
04001
04002
04003
04004
04005
04006
04007
04008 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
04009 {
04010 SQLHSTMT stmt;
04011 char sql[512];
04012 char msgnums[20];
04013 char msgnumd[20];
04014 char msg_id[MSG_ID_LEN];
04015 struct odbc_obj *obj;
04016 char *argv[] = { ddir, msgnumd, msg_id, dmailboxuser, dmailboxcontext, sdir, msgnums };
04017 struct generic_prepare_struct gps = { .sql = sql, .argc = 7, .argv = argv };
04018
04019 generate_msg_id(msg_id);
04020 delete_file(ddir, dmsg);
04021 obj = ast_odbc_request_obj(odbc_database, 0);
04022 if (obj) {
04023 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
04024 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
04025 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, msg_id, 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);
04026 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
04027 if (!stmt)
04028 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
04029 else
04030 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
04031 ast_odbc_release_obj(obj);
04032 } else
04033 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
04034 return;
04035 }
04036
04037 struct insert_data {
04038 char *sql;
04039 const char *dir;
04040 const char *msgnums;
04041 void *data;
04042 SQLLEN datalen;
04043 SQLLEN indlen;
04044 const char *context;
04045 const char *macrocontext;
04046 const char *callerid;
04047 const char *origtime;
04048 const char *duration;
04049 const char *mailboxuser;
04050 const char *mailboxcontext;
04051 const char *category;
04052 const char *flag;
04053 const char *msg_id;
04054 };
04055
04056 static SQLHSTMT insert_data_cb(struct odbc_obj *obj, void *vdata)
04057 {
04058 struct insert_data *data = vdata;
04059 int res;
04060 SQLHSTMT stmt;
04061
04062 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
04063 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04064 ast_log(AST_LOG_WARNING, "SQL Alloc Handle failed!\n");
04065 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
04066 return NULL;
04067 }
04068
04069 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (void *) data->dir, 0, NULL);
04070 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (void *) data->msgnums, 0, NULL);
04071 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (void *) data->data, data->datalen, &data->indlen);
04072 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (void *) data->context, 0, NULL);
04073 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (void *) data->macrocontext, 0, NULL);
04074 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (void *) data->callerid, 0, NULL);
04075 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (void *) data->origtime, 0, NULL);
04076 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (void *) data->duration, 0, NULL);
04077 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (void *) data->mailboxuser, 0, NULL);
04078 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (void *) data->mailboxcontext, 0, NULL);
04079 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (void *) data->flag, 0, NULL);
04080 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msg_id), 0, (void *) data->msg_id, 0, NULL);
04081 if (!ast_strlen_zero(data->category)) {
04082 SQLBindParameter(stmt, 13, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (void *) data->category, 0, NULL);
04083 }
04084 res = SQLExecDirect(stmt, (unsigned char *) data->sql, SQL_NTS);
04085 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
04086 ast_log(AST_LOG_WARNING, "SQL Direct Execute failed!\n");
04087 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
04088 return NULL;
04089 }
04090
04091 return stmt;
04092 }
04093
04094
04095
04096
04097
04098
04099
04100
04101
04102
04103
04104
04105
04106
04107 static int store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum)
04108 {
04109 int res = 0;
04110 int fd = -1;
04111 void *fdm = MAP_FAILED;
04112 off_t fdlen = -1;
04113 SQLHSTMT stmt;
04114 char sql[PATH_MAX];
04115 char msgnums[20];
04116 char fn[PATH_MAX];
04117 char full_fn[PATH_MAX];
04118 char fmt[80]="";
04119 char *c;
04120 struct ast_config *cfg = NULL;
04121 struct odbc_obj *obj;
04122 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
04123 .context = "", .macrocontext = "", .callerid = "", .origtime = "", .duration = "", .category = "", .flag = "", .msg_id = "" };
04124 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04125
04126 delete_file(dir, msgnum);
04127 if (!(obj = ast_odbc_request_obj(odbc_database, 0))) {
04128 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
04129 return -1;
04130 }
04131
04132 do {
04133 ast_copy_string(fmt, vmfmts, sizeof(fmt));
04134 c = strchr(fmt, '|');
04135 if (c)
04136 *c = '\0';
04137 if (!strcasecmp(fmt, "wav49"))
04138 strcpy(fmt, "WAV");
04139 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
04140 if (msgnum > -1)
04141 make_file(fn, sizeof(fn), dir, msgnum);
04142 else
04143 ast_copy_string(fn, dir, sizeof(fn));
04144 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
04145 cfg = ast_config_load(full_fn, config_flags);
04146 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
04147 fd = open(full_fn, O_RDWR);
04148 if (fd < 0) {
04149 ast_log(AST_LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
04150 res = -1;
04151 break;
04152 }
04153 if (valid_config(cfg)) {
04154 if (!(idata.context = ast_variable_retrieve(cfg, "message", "context"))) {
04155 idata.context = "";
04156 }
04157 if (!(idata.macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext"))) {
04158 idata.macrocontext = "";
04159 }
04160 if (!(idata.callerid = ast_variable_retrieve(cfg, "message", "callerid"))) {
04161 idata.callerid = "";
04162 }
04163 if (!(idata.origtime = ast_variable_retrieve(cfg, "message", "origtime"))) {
04164 idata.origtime = "";
04165 }
04166 if (!(idata.duration = ast_variable_retrieve(cfg, "message", "duration"))) {
04167 idata.duration = "";
04168 }
04169 if (!(idata.category = ast_variable_retrieve(cfg, "message", "category"))) {
04170 idata.category = "";
04171 }
04172 if (!(idata.flag = ast_variable_retrieve(cfg, "message", "flag"))) {
04173 idata.flag = "";
04174 }
04175 if (!(idata.msg_id = ast_variable_retrieve(cfg, "message", "msg_id"))) {
04176 idata.msg_id = "";
04177 }
04178 }
04179 fdlen = lseek(fd, 0, SEEK_END);
04180 if (fdlen < 0 || lseek(fd, 0, SEEK_SET) < 0) {
04181 ast_log(AST_LOG_WARNING, "Failed to process sound file '%s': %s\n", full_fn, strerror(errno));
04182 res = -1;
04183 break;
04184 }
04185 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
04186 if (fdm == MAP_FAILED) {
04187 ast_log(AST_LOG_WARNING, "Memory map failed for sound file '%s'!\n", full_fn);
04188 res = -1;
04189 break;
04190 }
04191 idata.data = fdm;
04192 idata.datalen = idata.indlen = fdlen;
04193
04194 if (!ast_strlen_zero(idata.category))
04195 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,msg_id,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
04196 else
04197 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,msg_id) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
04198
04199 if ((stmt = ast_odbc_direct_execute(obj, insert_data_cb, &idata))) {
04200 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
04201 } else {
04202 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
04203 res = -1;
04204 }
04205 } while (0);
04206 if (obj) {
04207 ast_odbc_release_obj(obj);
04208 }
04209 if (valid_config(cfg))
04210 ast_config_destroy(cfg);
04211 if (fdm != MAP_FAILED)
04212 munmap(fdm, fdlen);
04213 if (fd > -1)
04214 close(fd);
04215 return res;
04216 }
04217
04218
04219
04220
04221
04222
04223
04224
04225
04226
04227
04228
04229
04230
04231 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
04232 {
04233 SQLHSTMT stmt;
04234 char sql[PATH_MAX];
04235 char msgnums[20];
04236 char msgnumd[20];
04237 struct odbc_obj *obj;
04238 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
04239 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
04240
04241 delete_file(ddir, dmsg);
04242 obj = ast_odbc_request_obj(odbc_database, 0);
04243 if (obj) {
04244 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
04245 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
04246 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
04247 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
04248 if (!stmt)
04249 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
04250 else
04251 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
04252 ast_odbc_release_obj(obj);
04253 } else
04254 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
04255 return;
04256 }
04257
04258
04259
04260
04261
04262
04263
04264
04265
04266
04267
04268
04269 static int remove_file(char *dir, int msgnum)
04270 {
04271 char fn[PATH_MAX];
04272 char full_fn[PATH_MAX];
04273 char msgnums[80];
04274
04275 if (msgnum > -1) {
04276 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
04277 make_file(fn, sizeof(fn), dir, msgnum);
04278 } else
04279 ast_copy_string(fn, dir, sizeof(fn));
04280 ast_filedelete(fn, NULL);
04281 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
04282 unlink(full_fn);
04283 return 0;
04284 }
04285 #else
04286 #ifndef IMAP_STORAGE
04287
04288
04289
04290
04291
04292
04293
04294
04295
04296 static int count_messages(struct ast_vm_user *vmu, char *dir)
04297 {
04298
04299 int vmcount = 0;
04300 DIR *vmdir = NULL;
04301 struct dirent *vment = NULL;
04302
04303 if (vm_lock_path(dir))
04304 return ERROR_LOCK_PATH;
04305
04306 if ((vmdir = opendir(dir))) {
04307 while ((vment = readdir(vmdir))) {
04308 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4)) {
04309 vmcount++;
04310 }
04311 }
04312 closedir(vmdir);
04313 }
04314 ast_unlock_path(dir);
04315
04316 return vmcount;
04317 }
04318
04319
04320
04321
04322
04323
04324
04325
04326 static void rename_file(char *sfn, char *dfn)
04327 {
04328 char stxt[PATH_MAX];
04329 char dtxt[PATH_MAX];
04330 ast_filerename(sfn, dfn, NULL);
04331 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
04332 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
04333 if (ast_check_realtime("voicemail_data")) {
04334 ast_update_realtime("voicemail_data", "filename", sfn, "filename", dfn, SENTINEL);
04335 }
04336 rename(stxt, dtxt);
04337 }
04338
04339
04340
04341
04342
04343
04344
04345
04346
04347
04348
04349
04350 static int last_message_index(struct ast_vm_user *vmu, char *dir)
04351 {
04352 int x;
04353 unsigned char map[MAXMSGLIMIT] = "";
04354 DIR *msgdir;
04355 struct dirent *msgdirent;
04356 int msgdirint;
04357 char extension[4];
04358 int stopcount = 0;
04359
04360
04361
04362
04363
04364 if (!(msgdir = opendir(dir))) {
04365 return -1;
04366 }
04367
04368 while ((msgdirent = readdir(msgdir))) {
04369 if (sscanf(msgdirent->d_name, "msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension, "txt") && msgdirint < MAXMSGLIMIT) {
04370 map[msgdirint] = 1;
04371 stopcount++;
04372 ast_debug(4, "%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
04373 }
04374 }
04375 closedir(msgdir);
04376
04377 for (x = 0; x < vmu->maxmsg; x++) {
04378 if (map[x] == 1) {
04379 stopcount--;
04380 } else if (map[x] == 0 && !stopcount) {
04381 break;
04382 }
04383 }
04384
04385 return x - 1;
04386 }
04387
04388 #endif
04389 #endif
04390 #ifndef IMAP_STORAGE
04391
04392
04393
04394
04395
04396
04397
04398
04399
04400
04401 static int copy(char *infile, char *outfile)
04402 {
04403 int ifd;
04404 int ofd;
04405 int res;
04406 int len;
04407 char buf[4096];
04408
04409 #ifdef HARDLINK_WHEN_POSSIBLE
04410
04411 if (link(infile, outfile)) {
04412 #endif
04413 if ((ifd = open(infile, O_RDONLY)) < 0) {
04414 ast_log(AST_LOG_WARNING, "Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
04415 return -1;
04416 }
04417 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
04418 ast_log(AST_LOG_WARNING, "Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
04419 close(ifd);
04420 return -1;
04421 }
04422 do {
04423 len = read(ifd, buf, sizeof(buf));
04424 if (len < 0) {
04425 ast_log(AST_LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
04426 close(ifd);
04427 close(ofd);
04428 unlink(outfile);
04429 } else if (len) {
04430 res = write(ofd, buf, len);
04431 if (errno == ENOMEM || errno == ENOSPC || res != len) {
04432 ast_log(AST_LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
04433 close(ifd);
04434 close(ofd);
04435 unlink(outfile);
04436 }
04437 }
04438 } while (len);
04439 close(ifd);
04440 close(ofd);
04441 return 0;
04442 #ifdef HARDLINK_WHEN_POSSIBLE
04443 } else {
04444
04445 return 0;
04446 }
04447 #endif
04448 }
04449
04450
04451
04452
04453
04454
04455
04456
04457
04458
04459 static void copy_plain_file(char *frompath, char *topath)
04460 {
04461 char frompath2[PATH_MAX], topath2[PATH_MAX];
04462 struct ast_variable *tmp,*var = NULL;
04463 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
04464 ast_filecopy(frompath, topath, NULL);
04465 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
04466 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
04467 if (ast_check_realtime("voicemail_data")) {
04468 var = ast_load_realtime("voicemail_data", "filename", frompath, SENTINEL);
04469
04470 for (tmp = var; tmp; tmp = tmp->next) {
04471 if (!strcasecmp(tmp->name, "origmailbox")) {
04472 origmailbox = tmp->value;
04473 } else if (!strcasecmp(tmp->name, "context")) {
04474 context = tmp->value;
04475 } else if (!strcasecmp(tmp->name, "macrocontext")) {
04476 macrocontext = tmp->value;
04477 } else if (!strcasecmp(tmp->name, "exten")) {
04478 exten = tmp->value;
04479 } else if (!strcasecmp(tmp->name, "priority")) {
04480 priority = tmp->value;
04481 } else if (!strcasecmp(tmp->name, "callerchan")) {
04482 callerchan = tmp->value;
04483 } else if (!strcasecmp(tmp->name, "callerid")) {
04484 callerid = tmp->value;
04485 } else if (!strcasecmp(tmp->name, "origdate")) {
04486 origdate = tmp->value;
04487 } else if (!strcasecmp(tmp->name, "origtime")) {
04488 origtime = tmp->value;
04489 } else if (!strcasecmp(tmp->name, "category")) {
04490 category = tmp->value;
04491 } else if (!strcasecmp(tmp->name, "duration")) {
04492 duration = tmp->value;
04493 }
04494 }
04495 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);
04496 }
04497 copy(frompath2, topath2);
04498 ast_variables_destroy(var);
04499 }
04500 #endif
04501
04502
04503
04504
04505
04506
04507
04508
04509
04510 static int vm_delete(char *file)
04511 {
04512 char *txt;
04513 int txtsize = 0;
04514
04515 txtsize = (strlen(file) + 5)*sizeof(char);
04516 txt = ast_alloca(txtsize);
04517
04518
04519
04520 if (ast_check_realtime("voicemail_data")) {
04521 ast_destroy_realtime("voicemail_data", "filename", file, SENTINEL);
04522 }
04523 snprintf(txt, txtsize, "%s.txt", file);
04524 unlink(txt);
04525 return ast_filedelete(file, NULL);
04526 }
04527
04528
04529
04530
04531 static int inbuf(struct baseio *bio, FILE *fi)
04532 {
04533 int l;
04534
04535 if (bio->ateof)
04536 return 0;
04537
04538 if ((l = fread(bio->iobuf, 1, BASEMAXINLINE, fi)) <= 0) {
04539 if (ferror(fi))
04540 return -1;
04541
04542 bio->ateof = 1;
04543 return 0;
04544 }
04545
04546 bio->iolen = l;
04547 bio->iocp = 0;
04548
04549 return 1;
04550 }
04551
04552
04553
04554
04555 static int inchar(struct baseio *bio, FILE *fi)
04556 {
04557 if (bio->iocp>=bio->iolen) {
04558 if (!inbuf(bio, fi))
04559 return EOF;
04560 }
04561
04562 return bio->iobuf[bio->iocp++];
04563 }
04564
04565
04566
04567
04568 static int ochar(struct baseio *bio, int c, FILE *so)
04569 {
04570 if (bio->linelength >= BASELINELEN) {
04571 if (fputs(ENDL, so) == EOF) {
04572 return -1;
04573 }
04574
04575 bio->linelength = 0;
04576 }
04577
04578 if (putc(((unsigned char) c), so) == EOF) {
04579 return -1;
04580 }
04581
04582 bio->linelength++;
04583
04584 return 1;
04585 }
04586
04587
04588
04589
04590
04591
04592
04593
04594
04595
04596 static int base_encode(char *filename, FILE *so)
04597 {
04598 static const unsigned char dtable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
04599 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
04600 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0',
04601 '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
04602 int i, hiteof = 0;
04603 FILE *fi;
04604 struct baseio bio;
04605
04606 memset(&bio, 0, sizeof(bio));
04607 bio.iocp = BASEMAXINLINE;
04608
04609 if (!(fi = fopen(filename, "rb"))) {
04610 ast_log(AST_LOG_WARNING, "Failed to open file: %s: %s\n", filename, strerror(errno));
04611 return -1;
04612 }
04613
04614 while (!hiteof){
04615 unsigned char igroup[3], ogroup[4];
04616 int c, n;
04617
04618 memset(igroup, 0, sizeof(igroup));
04619
04620 for (n = 0; n < 3; n++) {
04621 if ((c = inchar(&bio, fi)) == EOF) {
04622 hiteof = 1;
04623 break;
04624 }
04625
04626 igroup[n] = (unsigned char) c;
04627 }
04628
04629 if (n > 0) {
04630 ogroup[0]= dtable[igroup[0] >> 2];
04631 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
04632 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
04633 ogroup[3]= dtable[igroup[2] & 0x3F];
04634
04635 if (n < 3) {
04636 ogroup[3] = '=';
04637
04638 if (n < 2)
04639 ogroup[2] = '=';
04640 }
04641
04642 for (i = 0; i < 4; i++)
04643 ochar(&bio, ogroup[i], so);
04644 }
04645 }
04646
04647 fclose(fi);
04648
04649 if (fputs(ENDL, so) == EOF) {
04650 return 0;
04651 }
04652
04653 return 1;
04654 }
04655
04656 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)
04657 {
04658 char callerid[256];
04659 char num[12];
04660 char fromdir[256], fromfile[256];
04661 struct ast_config *msg_cfg;
04662 const char *origcallerid, *origtime;
04663 char origcidname[80], origcidnum[80], origdate[80];
04664 int inttime;
04665 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
04666
04667
04668 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
04669 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
04670 snprintf(num, sizeof(num), "%d", msgnum);
04671 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
04672 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
04673 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
04674 pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
04675 ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, NULL) : "an unknown caller");
04676 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (!ast_strlen_zero(cidname) ? cidname : "an unknown caller"));
04677 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (!ast_strlen_zero(cidnum) ? cidnum : "an unknown caller"));
04678 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
04679 pbx_builtin_setvar_helper(ast, "VM_CATEGORY", category ? ast_strdupa(category) : "no category");
04680 pbx_builtin_setvar_helper(ast, "VM_FLAG", flag);
04681
04682
04683 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
04684 make_file(fromfile, sizeof(fromfile), fromdir, msgnum - 1);
04685 if (strlen(fromfile) < sizeof(fromfile) - 5) {
04686 strcat(fromfile, ".txt");
04687 }
04688 if (!(msg_cfg = ast_config_load(fromfile, config_flags)) || !(valid_config(msg_cfg))) {
04689 ast_debug(1, "Config load for message text file '%s' failed\n", fromfile);
04690 return;
04691 }
04692
04693 if ((origcallerid = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
04694 pbx_builtin_setvar_helper(ast, "ORIG_VM_CALLERID", origcallerid);
04695 ast_callerid_split(origcallerid, origcidname, sizeof(origcidname), origcidnum, sizeof(origcidnum));
04696 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNAME", origcidname);
04697 pbx_builtin_setvar_helper(ast, "ORIG_VM_CIDNUM", origcidnum);
04698 }
04699
04700 if ((origtime = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(origtime, "%30d", &inttime) == 1) {
04701 struct timeval tv = { inttime, };
04702 struct ast_tm tm;
04703 ast_localtime(&tv, &tm, NULL);
04704 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04705 pbx_builtin_setvar_helper(ast, "ORIG_VM_DATE", origdate);
04706 }
04707 ast_config_destroy(msg_cfg);
04708 }
04709
04710
04711
04712
04713
04714
04715
04716
04717
04718 static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
04719 {
04720 const char *ptr;
04721
04722
04723 ast_str_set(buf, maxlen, "\"");
04724 for (ptr = from; *ptr; ptr++) {
04725 if (*ptr == '"' || *ptr == '\\') {
04726 ast_str_append(buf, maxlen, "\\%c", *ptr);
04727 } else {
04728 ast_str_append(buf, maxlen, "%c", *ptr);
04729 }
04730 }
04731 ast_str_append(buf, maxlen, "\"");
04732
04733 return ast_str_buffer(*buf);
04734 }
04735
04736
04737
04738
04739
04740 static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
04741 {
04742 const struct vm_zone *z = NULL;
04743 struct timeval t = ast_tvnow();
04744
04745
04746 if (!ast_strlen_zero(vmu->zonetag)) {
04747
04748 AST_LIST_LOCK(&zones);
04749 AST_LIST_TRAVERSE(&zones, z, list) {
04750 if (!strcmp(z->name, vmu->zonetag))
04751 break;
04752 }
04753 AST_LIST_UNLOCK(&zones);
04754 }
04755 ast_localtime(&t, tm, z ? z->timezone : NULL);
04756 return tm;
04757 }
04758
04759
04760
04761
04762
04763 static int check_mime(const char *str)
04764 {
04765 for (; *str; str++) {
04766 if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
04767 return 1;
04768 }
04769 }
04770 return 0;
04771 }
04772
04773
04774
04775
04776
04777
04778
04779
04780
04781
04782
04783
04784
04785
04786
04787
04788
04789
04790 static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
04791 {
04792 struct ast_str *tmp = ast_str_alloca(80);
04793 int first_section = 1;
04794
04795 ast_str_reset(*end);
04796 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04797 for (; *start; start++) {
04798 int need_encoding = 0;
04799 if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
04800 need_encoding = 1;
04801 }
04802 if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
04803 (first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
04804 (!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
04805 (!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
04806
04807 ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
04808 ast_str_set(&tmp, -1, "=?%s?Q?", charset);
04809 first_section = 0;
04810 }
04811 if (need_encoding && *start == ' ') {
04812 ast_str_append(&tmp, -1, "_");
04813 } else if (need_encoding) {
04814 ast_str_append(&tmp, -1, "=%hhX", *start);
04815 } else {
04816 ast_str_append(&tmp, -1, "%c", *start);
04817 }
04818 }
04819 ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
04820 return ast_str_buffer(*end);
04821 }
04822
04823
04824
04825
04826
04827
04828
04829
04830
04831
04832
04833
04834
04835
04836
04837
04838
04839
04840
04841
04842
04843
04844
04845
04846 static void make_email_file(FILE *p,
04847 char *srcemail,
04848 struct ast_vm_user *vmu,
04849 int msgnum,
04850 char *context,
04851 char *mailbox,
04852 const char *fromfolder,
04853 char *cidnum,
04854 char *cidname,
04855 char *attach,
04856 char *attach2,
04857 char *format,
04858 int duration,
04859 int attach_user_voicemail,
04860 struct ast_channel *chan,
04861 const char *category,
04862 int imap,
04863 const char *flag,
04864 const char *msg_id)
04865 {
04866 char date[256];
04867 char host[MAXHOSTNAMELEN] = "";
04868 char who[256];
04869 char bound[256];
04870 char dur[256];
04871 struct ast_tm tm;
04872 char enc_cidnum[256] = "", enc_cidname[256] = "";
04873 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
04874 char *greeting_attachment;
04875 char filename[256];
04876
04877 if (!str1 || !str2) {
04878 ast_free(str1);
04879 ast_free(str2);
04880 return;
04881 }
04882
04883 if (cidnum) {
04884 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
04885 }
04886 if (cidname) {
04887 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
04888 }
04889 gethostname(host, sizeof(host) - 1);
04890
04891 if (strchr(srcemail, '@')) {
04892 ast_copy_string(who, srcemail, sizeof(who));
04893 } else {
04894 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
04895 }
04896
04897 greeting_attachment = strrchr(ast_strdupa(attach), '/');
04898 if (greeting_attachment) {
04899 *greeting_attachment++ = '\0';
04900 }
04901
04902 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
04903 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
04904 fprintf(p, "Date: %s" ENDL, date);
04905
04906
04907 ast_strftime_locale(date, sizeof(date), emaildateformat, &tm, S_OR(vmu->locale, NULL));
04908
04909 if (!ast_strlen_zero(fromstring)) {
04910 struct ast_channel *ast;
04911 if ((ast = ast_dummy_channel_alloc())) {
04912 char *ptr;
04913 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
04914 ast_str_substitute_variables(&str1, 0, ast, fromstring);
04915
04916 if (check_mime(ast_str_buffer(str1))) {
04917 int first_line = 1;
04918 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
04919 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04920 *ptr = '\0';
04921 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
04922 first_line = 0;
04923
04924 ast_str_set(&str2, 0, "%s", ptr + 1);
04925 }
04926 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
04927 } else {
04928 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
04929 }
04930 ast = ast_channel_unref(ast);
04931 } else {
04932 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04933 }
04934 } else {
04935 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
04936 }
04937
04938 if (check_mime(vmu->fullname)) {
04939 int first_line = 1;
04940 char *ptr;
04941 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
04942 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04943 *ptr = '\0';
04944 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
04945 first_line = 0;
04946
04947 ast_str_set(&str2, 0, "%s", ptr + 1);
04948 }
04949 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
04950 } else {
04951 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
04952 }
04953
04954 if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
04955 char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
04956 struct ast_channel *ast;
04957 if ((ast = ast_dummy_channel_alloc())) {
04958 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
04959 ast_str_substitute_variables(&str1, 0, ast, e_subj);
04960 if (check_mime(ast_str_buffer(str1))) {
04961 int first_line = 1;
04962 char *ptr;
04963 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
04964 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
04965 *ptr = '\0';
04966 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04967 first_line = 0;
04968
04969 ast_str_set(&str2, 0, "%s", ptr + 1);
04970 }
04971 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
04972 } else {
04973 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
04974 }
04975 ast = ast_channel_unref(ast);
04976 } else {
04977 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
04978 }
04979 } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) {
04980 if (ast_strlen_zero(flag)) {
04981 fprintf(p, "Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04982 } else {
04983 fprintf(p, "Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04984 }
04985 } else {
04986 if (ast_strlen_zero(flag)) {
04987 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
04988 } else {
04989 fprintf(p, "Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
04990 }
04991 }
04992
04993 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>" ENDL, msgnum + 1,
04994 (unsigned int) ast_random(), mailbox, (int) getpid(), host);
04995 if (imap) {
04996
04997 fprintf(p, "X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
04998
04999 fprintf(p, "X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
05000 fprintf(p, "X-Asterisk-VM-Context: %s" ENDL, context);
05001 #ifdef IMAP_STORAGE
05002 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
05003 #else
05004 fprintf(p, "X-Asterisk-VM-Extension: %s" ENDL, mailbox);
05005 #endif
05006
05007 fprintf(p, "X-Asterisk-VM-Flag: %s" ENDL, flag);
05008 fprintf(p, "X-Asterisk-VM-Priority: %d" ENDL, chan ? ast_channel_priority(chan) : 0);
05009 fprintf(p, "X-Asterisk-VM-Caller-channel: %s" ENDL, chan ? ast_channel_name(chan) : "");
05010 fprintf(p, "X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
05011 fprintf(p, "X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
05012 fprintf(p, "X-Asterisk-VM-Duration: %d" ENDL, duration);
05013 if (!ast_strlen_zero(category)) {
05014 fprintf(p, "X-Asterisk-VM-Category: %s" ENDL, category);
05015 } else {
05016 fprintf(p, "X-Asterisk-VM-Category: " ENDL);
05017 }
05018 fprintf(p, "X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ? "Message" : greeting_attachment);
05019 fprintf(p, "X-Asterisk-VM-Orig-date: %s" ENDL, date);
05020 fprintf(p, "X-Asterisk-VM-Orig-time: %ld" ENDL, (long) time(NULL));
05021 fprintf(p, "X-Asterisk-VM-Message-ID: %s" ENDL, msg_id);
05022 }
05023 if (!ast_strlen_zero(cidnum)) {
05024 fprintf(p, "X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
05025 }
05026 if (!ast_strlen_zero(cidname)) {
05027 fprintf(p, "X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
05028 }
05029 fprintf(p, "MIME-Version: 1.0" ENDL);
05030 if (attach_user_voicemail) {
05031
05032 snprintf(bound, sizeof(bound), "----voicemail_%d%s%d%d", msgnum + 1, mailbox,
05033 (int) getpid(), (unsigned int) ast_random());
05034
05035 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
05036 fprintf(p, ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
05037 fprintf(p, "--%s" ENDL, bound);
05038 }
05039 fprintf(p, "Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
05040 if (emailbody || vmu->emailbody) {
05041 char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
05042 struct ast_channel *ast;
05043 if ((ast = ast_dummy_channel_alloc())) {
05044 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05045 ast_str_substitute_variables(&str1, 0, ast, e_body);
05046 #ifdef IMAP_STORAGE
05047 {
05048
05049 char *line = ast_str_buffer(str1), *next;
05050 do {
05051
05052 if ((next = strchr(line, '\n'))) {
05053 *next++ = '\0';
05054 }
05055 fprintf(p, "%s" ENDL, line);
05056 line = next;
05057 } while (!ast_strlen_zero(line));
05058 }
05059 #else
05060 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
05061 #endif
05062 ast = ast_channel_unref(ast);
05063 } else {
05064 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05065 }
05066 } else if (msgnum > -1) {
05067 if (strcmp(vmu->mailbox, mailbox)) {
05068
05069 struct ast_config *msg_cfg;
05070 const char *v;
05071 int inttime;
05072 char fromdir[256], fromfile[256], origdate[80] = "", origcallerid[80] = "";
05073 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
05074
05075 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, fromfolder);
05076 make_file(fromfile, sizeof(fromfile), fromdir, msgnum);
05077 if (strlen(fromfile) < sizeof(fromfile) - 5) {
05078 strcat(fromfile, ".txt");
05079 }
05080 if ((msg_cfg = ast_config_load(fromfile, config_flags)) && valid_config(msg_cfg)) {
05081 if ((v = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
05082 ast_copy_string(origcallerid, v, sizeof(origcallerid));
05083 }
05084
05085
05086
05087 if ((v = ast_variable_retrieve(msg_cfg, "message", "origtime")) && sscanf(v, "%30d", &inttime) == 1) {
05088 struct timeval tv = { inttime, };
05089 struct ast_tm tm;
05090 ast_localtime(&tv, &tm, NULL);
05091 ast_strftime_locale(origdate, sizeof(origdate), emaildateformat, &tm, S_OR(vmu->locale, NULL));
05092 }
05093 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
05094 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
05095 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
05096 " chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk" ENDL ENDL, vmu->fullname, dur,
05097 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")),
05098 date, origcallerid, origdate);
05099 ast_config_destroy(msg_cfg);
05100 } else {
05101 goto plain_message;
05102 }
05103 } else {
05104 plain_message:
05105 fprintf(p, "Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
05106 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
05107 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
05108 ENDL ENDL, vmu->fullname, dur, msgnum + 1, mailbox,
05109 (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
05110 }
05111 } else {
05112 fprintf(p, "This message is to let you know that your greeting was changed on %s." ENDL
05113 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
05114 }
05115
05116 if (imap || attach_user_voicemail) {
05117 if (!ast_strlen_zero(attach2)) {
05118 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
05119 ast_debug(5, "creating second attachment filename %s\n", filename);
05120 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
05121 snprintf(filename, sizeof(filename), "msgintro%04d.%s", msgnum, format);
05122 ast_debug(5, "creating attachment filename %s\n", filename);
05123 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
05124 } else {
05125 snprintf(filename, sizeof(filename), "msg%04d.%s", msgnum, format);
05126 ast_debug(5, "creating attachment filename %s, no second attachment.\n", filename);
05127 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
05128 }
05129 }
05130 ast_free(str1);
05131 ast_free(str2);
05132 }
05133
05134 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)
05135 {
05136 char tmpdir[256], newtmp[256];
05137 char fname[256];
05138 char tmpcmd[256];
05139 int tmpfd = -1;
05140 int soxstatus = 0;
05141
05142
05143 char *ctype = (!strcasecmp(format, "ogg")) ? "application/" : "audio/x-";
05144
05145 if (vmu->volgain < -.001 || vmu->volgain > .001) {
05146 create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, vmu->mailbox, "tmp");
05147 snprintf(newtmp, sizeof(newtmp), "%s/XXXXXX", tmpdir);
05148 tmpfd = mkstemp(newtmp);
05149 chmod(newtmp, VOICEMAIL_FILE_MODE & ~my_umask);
05150 ast_debug(3, "newtmp: %s\n", newtmp);
05151 if (tmpfd > -1) {
05152 snprintf(tmpcmd, sizeof(tmpcmd), "sox -v %.4f %s.%s %s.%s", vmu->volgain, attach, format, newtmp, format);
05153 if ((soxstatus = ast_safe_system(tmpcmd)) == 0) {
05154 attach = newtmp;
05155 ast_debug(3, "VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->volgain, mailbox);
05156 } else {
05157 ast_log(LOG_WARNING, "Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
05158 soxstatus == 1 ? "Problem with command line options" : "An error occurred during file processing");
05159 ast_log(LOG_WARNING, "Voicemail attachment will have no volume gain.\n");
05160 }
05161 }
05162 }
05163 fprintf(p, "--%s" ENDL, bound);
05164 if (msgnum > -1)
05165 fprintf(p, "Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
05166 else
05167 fprintf(p, "Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
05168 fprintf(p, "Content-Transfer-Encoding: base64" ENDL);
05169 fprintf(p, "Content-Description: Voicemail sound attachment." ENDL);
05170 if (msgnum > -1)
05171 fprintf(p, "Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
05172 else
05173 fprintf(p, "Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
05174 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
05175 base_encode(fname, p);
05176 if (last)
05177 fprintf(p, ENDL ENDL "--%s--" ENDL "." ENDL, bound);
05178 if (tmpfd > -1) {
05179 if (soxstatus == 0) {
05180 unlink(fname);
05181 }
05182 close(tmpfd);
05183 unlink(newtmp);
05184 }
05185 return 0;
05186 }
05187
05188 static int sendmail(char *srcemail,
05189 struct ast_vm_user *vmu,
05190 int msgnum,
05191 char *context,
05192 char *mailbox,
05193 const char *fromfolder,
05194 char *cidnum,
05195 char *cidname,
05196 char *attach,
05197 char *attach2,
05198 char *format,
05199 int duration,
05200 int attach_user_voicemail,
05201 struct ast_channel *chan,
05202 const char *category,
05203 const char *flag,
05204 const char *msg_id)
05205 {
05206 FILE *p = NULL;
05207 char tmp[80] = "/tmp/astmail-XXXXXX";
05208 char tmp2[256];
05209 char *stringp;
05210
05211 if (vmu && ast_strlen_zero(vmu->email)) {
05212 ast_log(AST_LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
05213 return(0);
05214 }
05215
05216
05217 format = ast_strdupa(format);
05218 stringp = format;
05219 strsep(&stringp, "|");
05220
05221 if (!strcmp(format, "wav49"))
05222 format = "WAV";
05223 ast_debug(3, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
05224
05225
05226 if ((p = vm_mkftemp(tmp)) == NULL) {
05227 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
05228 return -1;
05229 } else {
05230 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag, msg_id);
05231 fclose(p);
05232 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
05233 ast_safe_system(tmp2);
05234 ast_debug(1, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
05235 }
05236 return 0;
05237 }
05238
05239 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)
05240 {
05241 char enc_cidnum[256], enc_cidname[256];
05242 char date[256];
05243 char host[MAXHOSTNAMELEN] = "";
05244 char who[256];
05245 char dur[PATH_MAX];
05246 char tmp[80] = "/tmp/astmail-XXXXXX";
05247 char tmp2[PATH_MAX];
05248 struct ast_tm tm;
05249 FILE *p;
05250 struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
05251
05252 if (!str1 || !str2) {
05253 ast_free(str1);
05254 ast_free(str2);
05255 return -1;
05256 }
05257
05258 if (cidnum) {
05259 strip_control_and_high(cidnum, enc_cidnum, sizeof(enc_cidnum));
05260 }
05261 if (cidname) {
05262 strip_control_and_high(cidname, enc_cidname, sizeof(enc_cidname));
05263 }
05264
05265 if ((p = vm_mkftemp(tmp)) == NULL) {
05266 ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
05267 ast_free(str1);
05268 ast_free(str2);
05269 return -1;
05270 }
05271 gethostname(host, sizeof(host)-1);
05272 if (strchr(srcemail, '@')) {
05273 ast_copy_string(who, srcemail, sizeof(who));
05274 } else {
05275 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
05276 }
05277 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
05278 ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
05279 fprintf(p, "Date: %s\n", date);
05280
05281
05282 ast_strftime_locale(date, sizeof(date), pagerdateformat, vmu_tm(vmu, &tm), S_OR(vmu->locale, NULL));
05283
05284 if (!ast_strlen_zero(pagerfromstring)) {
05285 struct ast_channel *ast;
05286 if ((ast = ast_dummy_channel_alloc())) {
05287 char *ptr;
05288 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
05289 ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
05290
05291 if (check_mime(ast_str_buffer(str1))) {
05292 int first_line = 1;
05293 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
05294 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
05295 *ptr = '\0';
05296 fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
05297 first_line = 0;
05298
05299 ast_str_set(&str2, 0, "%s", ptr + 1);
05300 }
05301 fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
05302 } else {
05303 fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
05304 }
05305 ast = ast_channel_unref(ast);
05306 } else {
05307 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05308 }
05309 } else {
05310 fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
05311 }
05312
05313 if (check_mime(vmu->fullname)) {
05314 int first_line = 1;
05315 char *ptr;
05316 ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
05317 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
05318 *ptr = '\0';
05319 fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
05320 first_line = 0;
05321
05322 ast_str_set(&str2, 0, "%s", ptr + 1);
05323 }
05324 fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
05325 } else {
05326 fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
05327 }
05328
05329 if (!ast_strlen_zero(pagersubject)) {
05330 struct ast_channel *ast;
05331 if ((ast = ast_dummy_channel_alloc())) {
05332 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05333 ast_str_substitute_variables(&str1, 0, ast, pagersubject);
05334 if (check_mime(ast_str_buffer(str1))) {
05335 int first_line = 1;
05336 char *ptr;
05337 ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
05338 while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
05339 *ptr = '\0';
05340 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05341 first_line = 0;
05342
05343 ast_str_set(&str2, 0, "%s", ptr + 1);
05344 }
05345 fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
05346 } else {
05347 fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
05348 }
05349 ast = ast_channel_unref(ast);
05350 } else {
05351 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05352 }
05353 } else {
05354 if (ast_strlen_zero(flag)) {
05355 fprintf(p, "Subject: New VM\n\n");
05356 } else {
05357 fprintf(p, "Subject: New %s VM\n\n", flag);
05358 }
05359 }
05360
05361 if (pagerbody) {
05362 struct ast_channel *ast;
05363 if ((ast = ast_dummy_channel_alloc())) {
05364 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
05365 ast_str_substitute_variables(&str1, 0, ast, pagerbody);
05366 fprintf(p, "%s" ENDL, ast_str_buffer(str1));
05367 ast = ast_channel_unref(ast);
05368 } else {
05369 ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
05370 }
05371 } else {
05372 fprintf(p, "New %s long %s msg in box %s\n"
05373 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
05374 }
05375
05376 fclose(p);
05377 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
05378 ast_safe_system(tmp2);
05379 ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
05380 ast_free(str1);
05381 ast_free(str2);
05382 return 0;
05383 }
05384
05385
05386
05387
05388
05389
05390
05391
05392
05393
05394 static int get_date(char *s, int len)
05395 {
05396 struct ast_tm tm;
05397 struct timeval t = ast_tvnow();
05398
05399 ast_localtime(&t, &tm, "UTC");
05400
05401 return ast_strftime(s, len, "%a %b %e %r UTC %Y", &tm);
05402 }
05403
05404 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
05405 {
05406 int res;
05407 char fn[PATH_MAX];
05408 char dest[PATH_MAX];
05409
05410 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
05411
05412 if ((res = create_dirpath(dest, sizeof(dest), context, ext, ""))) {
05413 ast_log(AST_LOG_WARNING, "Failed to make directory(%s)\n", fn);
05414 return -1;
05415 }
05416
05417 RETRIEVE(fn, -1, ext, context);
05418 if (ast_fileexists(fn, NULL, NULL) > 0) {
05419 res = ast_stream_and_wait(chan, fn, ecodes);
05420 if (res) {
05421 DISPOSE(fn, -1);
05422 return res;
05423 }
05424 } else {
05425
05426 DISPOSE(fn, -1);
05427 res = ast_stream_and_wait(chan, "vm-theperson", ecodes);
05428 if (res)
05429 return res;
05430 res = ast_say_digit_str(chan, ext, ecodes, ast_channel_language(chan));
05431 if (res)
05432 return res;
05433 }
05434 res = ast_stream_and_wait(chan, busy ? "vm-isonphone" : "vm-isunavail", ecodes);
05435 return res;
05436 }
05437
05438 static void free_zone(struct vm_zone *z)
05439 {
05440 ast_free(z);
05441 }
05442
05443 #ifdef ODBC_STORAGE
05444 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05445 {
05446 int x = -1;
05447 int res;
05448 SQLHSTMT stmt = NULL;
05449 char sql[PATH_MAX];
05450 char rowdata[20];
05451 char tmp[PATH_MAX] = "";
05452 struct odbc_obj *obj = NULL;
05453 char *context;
05454 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05455
05456 if (newmsgs)
05457 *newmsgs = 0;
05458 if (oldmsgs)
05459 *oldmsgs = 0;
05460 if (urgentmsgs)
05461 *urgentmsgs = 0;
05462
05463
05464 if (ast_strlen_zero(mailbox))
05465 return 0;
05466
05467 ast_copy_string(tmp, mailbox, sizeof(tmp));
05468
05469 if (strchr(mailbox, ' ') || strchr(mailbox, ',')) {
05470 int u, n, o;
05471 char *next, *remaining = tmp;
05472 while ((next = strsep(&remaining, " ,"))) {
05473 if (inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
05474 return -1;
05475 }
05476 if (urgentmsgs) {
05477 *urgentmsgs += u;
05478 }
05479 if (newmsgs) {
05480 *newmsgs += n;
05481 }
05482 if (oldmsgs) {
05483 *oldmsgs += o;
05484 }
05485 }
05486 return 0;
05487 }
05488
05489 context = strchr(tmp, '@');
05490 if (context) {
05491 *context = '\0';
05492 context++;
05493 } else
05494 context = "default";
05495
05496 if ((obj = ast_odbc_request_obj(odbc_database, 0))) {
05497 do {
05498 if (newmsgs) {
05499 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "INBOX");
05500 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05501 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05502 break;
05503 }
05504 res = SQLFetch(stmt);
05505 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05506 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05507 break;
05508 }
05509 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05510 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05511 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05512 break;
05513 }
05514 *newmsgs = atoi(rowdata);
05515 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05516 }
05517
05518 if (oldmsgs) {
05519 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Old");
05520 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05521 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05522 break;
05523 }
05524 res = SQLFetch(stmt);
05525 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05526 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05527 break;
05528 }
05529 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05530 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05531 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05532 break;
05533 }
05534 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
05535 *oldmsgs = atoi(rowdata);
05536 }
05537
05538 if (urgentmsgs) {
05539 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp, "Urgent");
05540 if (!(stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps))) {
05541 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05542 break;
05543 }
05544 res = SQLFetch(stmt);
05545 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05546 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05547 break;
05548 }
05549 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05550 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05551 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05552 break;
05553 }
05554 *urgentmsgs = atoi(rowdata);
05555 }
05556
05557 x = 0;
05558 } while (0);
05559 } else {
05560 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05561 }
05562
05563 if (stmt) {
05564 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05565 }
05566 if (obj) {
05567 ast_odbc_release_obj(obj);
05568 }
05569 return x;
05570 }
05571
05572
05573
05574
05575
05576
05577
05578
05579
05580
05581 static int messagecount(const char *context, const char *mailbox, const char *folder)
05582 {
05583 struct odbc_obj *obj = NULL;
05584 int nummsgs = 0;
05585 int res;
05586 SQLHSTMT stmt = NULL;
05587 char sql[PATH_MAX];
05588 char rowdata[20];
05589 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
05590
05591
05592 if (ast_strlen_zero(mailbox)) {
05593 return 0;
05594 }
05595
05596 if (ast_strlen_zero(folder)) {
05597 folder = "INBOX";
05598 }
05599
05600 obj = ast_odbc_request_obj(odbc_database, 0);
05601 if (obj) {
05602 if (!strcmp(folder, "INBOX")) {
05603 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);
05604 } else {
05605 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
05606 }
05607 stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
05608 if (!stmt) {
05609 ast_log(AST_LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
05610 goto yuck;
05611 }
05612 res = SQLFetch(stmt);
05613 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05614 ast_log(AST_LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
05615 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05616 goto yuck;
05617 }
05618 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
05619 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
05620 ast_log(AST_LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
05621 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05622 goto yuck;
05623 }
05624 nummsgs = atoi(rowdata);
05625 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
05626 } else
05627 ast_log(AST_LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
05628
05629 yuck:
05630 if (obj)
05631 ast_odbc_release_obj(obj);
05632 return nummsgs;
05633 }
05634
05635
05636
05637
05638
05639
05640
05641
05642
05643 static int has_voicemail(const char *mailbox, const char *folder)
05644 {
05645 char tmp[256], *tmp2 = tmp, *box, *context;
05646 ast_copy_string(tmp, mailbox, sizeof(tmp));
05647 while ((context = box = strsep(&tmp2, ",&"))) {
05648 strsep(&context, "@");
05649 if (ast_strlen_zero(context))
05650 context = "default";
05651 if (messagecount(context, box, folder))
05652 return 1;
05653 }
05654 return 0;
05655 }
05656 #endif
05657 #ifndef IMAP_STORAGE
05658
05659
05660
05661
05662
05663
05664
05665
05666
05667
05668
05669
05670
05671
05672
05673
05674 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, const char *dest_folder)
05675 {
05676 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
05677 const char *frombox = mbox(vmu, imbox);
05678 const char *userfolder;
05679 int recipmsgnum;
05680 int res = 0;
05681
05682 ast_log(AST_LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
05683
05684 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
05685 userfolder = "Urgent";
05686 } else if (!ast_strlen_zero(dest_folder)) {
05687 userfolder = dest_folder;
05688 } else {
05689 userfolder = "INBOX";
05690 }
05691
05692 create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05693
05694 if (!dir)
05695 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
05696 else
05697 ast_copy_string(fromdir, dir, sizeof(fromdir));
05698
05699 make_file(frompath, sizeof(frompath), fromdir, msgnum);
05700 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, userfolder);
05701
05702 if (vm_lock_path(todir))
05703 return ERROR_LOCK_PATH;
05704
05705 recipmsgnum = last_message_index(recip, todir) + 1;
05706 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->mailbox, vmu->context, 0))) {
05707 make_file(topath, sizeof(topath), todir, recipmsgnum);
05708 #ifndef ODBC_STORAGE
05709 if (EXISTS(fromdir, msgnum, frompath, chan ? ast_channel_language(chan) : "")) {
05710 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
05711 } else {
05712 #endif
05713
05714
05715
05716 copy_plain_file(frompath, topath);
05717 STORE(todir, recip->mailbox, recip->context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL, NULL);
05718 vm_delete(topath);
05719 #ifndef ODBC_STORAGE
05720 }
05721 #endif
05722 } else {
05723 ast_log(AST_LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
05724 res = -1;
05725 }
05726 ast_unlock_path(todir);
05727 if (chan) {
05728 struct ast_party_caller *caller = ast_channel_caller(chan);
05729 notify_new_message(chan, recip, NULL, recipmsgnum, duration, fmt,
05730 S_COR(caller->id.number.valid, caller->id.number.str, NULL),
05731 S_COR(caller->id.name.valid, caller->id.name.str, NULL),
05732 flag);
05733 }
05734
05735 return res;
05736 }
05737 #endif
05738 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
05739
05740 static int messagecount(const char *context, const char *mailbox, const char *folder)
05741 {
05742 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder, "INBOX") ? 0 : __has_voicemail(context, mailbox, "Urgent", 0));
05743 }
05744
05745 static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
05746 {
05747 DIR *dir;
05748 struct dirent *de;
05749 char fn[256];
05750 int ret = 0;
05751
05752
05753 if (ast_strlen_zero(mailbox))
05754 return 0;
05755
05756 if (ast_strlen_zero(folder))
05757 folder = "INBOX";
05758 if (ast_strlen_zero(context))
05759 context = "default";
05760
05761 snprintf(fn, sizeof(fn), "%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
05762
05763 if (!(dir = opendir(fn)))
05764 return 0;
05765
05766 while ((de = readdir(dir))) {
05767 if (!strncasecmp(de->d_name, "msg", 3)) {
05768 if (shortcircuit) {
05769 ret = 1;
05770 break;
05771 } else if (!strncasecmp(de->d_name + 8, "txt", 3)) {
05772 ret++;
05773 }
05774 }
05775 }
05776
05777 closedir(dir);
05778
05779 return ret;
05780 }
05781
05782
05783
05784
05785
05786
05787
05788
05789
05790
05791 static int has_voicemail(const char *mailbox, const char *folder)
05792 {
05793 char tmp[256], *tmp2 = tmp, *box, *context;
05794 ast_copy_string(tmp, mailbox, sizeof(tmp));
05795 if (ast_strlen_zero(folder)) {
05796 folder = "INBOX";
05797 }
05798 while ((box = strsep(&tmp2, ",&"))) {
05799 if ((context = strchr(box, '@')))
05800 *context++ = '\0';
05801 else
05802 context = "default";
05803 if (__has_voicemail(context, box, folder, 1))
05804 return 1;
05805
05806 if (!strcmp(folder, "INBOX") && __has_voicemail(context, box, "Urgent", 1)) {
05807 return 1;
05808 }
05809 }
05810 return 0;
05811 }
05812
05813
05814 static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
05815 {
05816 char tmp[256];
05817 char *context;
05818
05819
05820 if (ast_strlen_zero(mailbox))
05821 return 0;
05822
05823 if (newmsgs)
05824 *newmsgs = 0;
05825 if (oldmsgs)
05826 *oldmsgs = 0;
05827 if (urgentmsgs)
05828 *urgentmsgs = 0;
05829
05830 if (strchr(mailbox, ',')) {
05831 int tmpnew, tmpold, tmpurgent;
05832 char *mb, *cur;
05833
05834 ast_copy_string(tmp, mailbox, sizeof(tmp));
05835 mb = tmp;
05836 while ((cur = strsep(&mb, ", "))) {
05837 if (!ast_strlen_zero(cur)) {
05838 if (inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
05839 return -1;
05840 else {
05841 if (newmsgs)
05842 *newmsgs += tmpnew;
05843 if (oldmsgs)
05844 *oldmsgs += tmpold;
05845 if (urgentmsgs)
05846 *urgentmsgs += tmpurgent;
05847 }
05848 }
05849 }
05850 return 0;
05851 }
05852
05853 ast_copy_string(tmp, mailbox, sizeof(tmp));
05854
05855 if ((context = strchr(tmp, '@')))
05856 *context++ = '\0';
05857 else
05858 context = "default";
05859
05860 if (newmsgs)
05861 *newmsgs = __has_voicemail(context, tmp, "INBOX", 0);
05862 if (oldmsgs)
05863 *oldmsgs = __has_voicemail(context, tmp, "Old", 0);
05864 if (urgentmsgs)
05865 *urgentmsgs = __has_voicemail(context, tmp, "Urgent", 0);
05866
05867 return 0;
05868 }
05869
05870 #endif
05871
05872
05873 static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
05874 {
05875 int urgentmsgs = 0;
05876 int res = inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
05877 if (newmsgs) {
05878 *newmsgs += urgentmsgs;
05879 }
05880 return res;
05881 }
05882
05883 static void run_externnotify(char *context, char *extension, const char *flag)
05884 {
05885 char arguments[255];
05886 char ext_context[256] = "";
05887 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
05888 struct ast_smdi_mwi_message *mwi_msg;
05889
05890 if (!ast_strlen_zero(context))
05891 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
05892 else
05893 ast_copy_string(ext_context, extension, sizeof(ext_context));
05894
05895 if (smdi_iface) {
05896 if (ast_app_has_voicemail(ext_context, NULL))
05897 ast_smdi_mwi_set(smdi_iface, extension);
05898 else
05899 ast_smdi_mwi_unset(smdi_iface, extension);
05900
05901 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
05902 ast_log(AST_LOG_ERROR, "Error executing SMDI MWI change for %s\n", extension);
05903 if (!strncmp(mwi_msg->cause, "INV", 3))
05904 ast_log(AST_LOG_ERROR, "Invalid MWI extension: %s\n", mwi_msg->fwd_st);
05905 else if (!strncmp(mwi_msg->cause, "BLK", 3))
05906 ast_log(AST_LOG_WARNING, "MWI light was already on or off for %s\n", mwi_msg->fwd_st);
05907 ast_log(AST_LOG_WARNING, "The switch reported '%s'\n", mwi_msg->cause);
05908 ASTOBJ_UNREF(mwi_msg, ast_smdi_mwi_message_destroy);
05909 } else {
05910 ast_debug(1, "Successfully executed SMDI MWI change for %s\n", extension);
05911 }
05912 }
05913
05914 if (!ast_strlen_zero(externnotify)) {
05915 if (inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
05916 ast_log(AST_LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
05917 } else {
05918 snprintf(arguments, sizeof(arguments), "%s %s %s %d %d %d &",
05919 externnotify, S_OR(context, "\"\""),
05920 extension, newvoicemails,
05921 oldvoicemails, urgentvoicemails);
05922 ast_debug(1, "Executing %s\n", arguments);
05923 ast_safe_system(arguments);
05924 }
05925 }
05926 }
05927
05928
05929
05930
05931
05932
05933 struct leave_vm_options {
05934 unsigned int flags;
05935 signed char record_gain;
05936 char *exitcontext;
05937 };
05938
05939 static void generate_msg_id(char *dst)
05940 {
05941
05942
05943
05944
05945 int unique_counter = ast_atomic_fetchadd_int(&msg_id_incrementor, +1);
05946 snprintf(dst, MSG_ID_LEN, "%ld-%08x", (long) time(NULL), unique_counter);
05947 }
05948
05949
05950
05951
05952
05953
05954
05955
05956
05957
05958
05959
05960
05961
05962
05963 static int msg_create_from_file(struct ast_vm_recording_data *recdata)
05964 {
05965
05966 struct ast_vm_user *recipient;
05967 struct ast_vm_user svm;
05968
05969
05970 char tmpdir[PATH_MAX];
05971 char tmptxtfile[PATH_MAX];
05972 char desttxtfile[PATH_MAX];
05973 char tmpaudiofile[PATH_MAX];
05974 char dir[PATH_MAX];
05975 char destination[PATH_MAX];
05976
05977
05978 #ifdef IMAP_STORAGE
05979 struct vm_state *vms = NULL;
05980 char ext_context[256] = "";
05981 char *fmt = ast_strdupa(recdata->recording_ext);
05982 int newmsgs = 0;
05983 int oldmsgs = 0;
05984 #endif
05985
05986
05987 int res = 0;
05988 int txtdes ;
05989 FILE *txt;
05990 char date[256];
05991 int msgnum;
05992 int duration = 0;
05993 struct ast_filestream *recording_fs;
05994
05995
05996
05997 const char *category = NULL;
05998 char msg_id[MSG_ID_LEN];
05999
06000
06001 if (!(ast_fileexists(recdata->recording_file, recdata->recording_ext, NULL))) {
06002 ast_log(LOG_ERROR, "File: %s not found.\n", recdata->recording_file);
06003 return -1;
06004 }
06005
06006 if (!(recipient = find_user(&svm, recdata->context, recdata->mailbox))) {
06007 ast_log(LOG_ERROR, "No entry in voicemail config file for '%s@%s'\n", recdata->mailbox, recdata->context);
06008 return -1;
06009 }
06010
06011
06012 if ((recording_fs = ast_readfile(recdata->recording_file, recdata->recording_ext, NULL, 0, 0, VOICEMAIL_DIR_MODE))) {
06013 if (!ast_seekstream(recording_fs, 0, SEEK_END)) {
06014 long framelength = ast_tellstream(recording_fs);
06015 struct ast_format result = {0,};
06016
06017
06018
06019
06020 ast_getformatbyname(recdata->recording_ext, &result);
06021 duration = (int) (framelength / ast_format_rate(&result));
06022 }
06023 }
06024
06025
06026 if (duration < recipient->minsecs) {
06027 ast_log(LOG_NOTICE, "Copying recording to voicemail %s@%s skipped because duration was shorter than "
06028 "minmessage of recipient\n", recdata->mailbox, recdata->context);
06029 return -1;
06030 }
06031
06032
06033
06034 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), recipient->context, recdata->mailbox, "tmp"))) {
06035 ast_log(LOG_ERROR, "Failed to make directory.\n");
06036 }
06037
06038 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
06039 txtdes = mkstemp(tmptxtfile);
06040 if (txtdes < 0) {
06041 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
06042
06043 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
06044 free_user(recipient);
06045 return -1;
06046 }
06047
06048
06049 txt = fdopen(txtdes, "w+");
06050 if (txt) {
06051 generate_msg_id(msg_id);
06052 get_date(date, sizeof(date));
06053 fprintf(txt,
06054 ";\n"
06055 "; Message Information file\n"
06056 ";\n"
06057 "[message]\n"
06058 "origmailbox=%s\n"
06059 "context=%s\n"
06060 "macrocontext=%s\n"
06061 "exten=%s\n"
06062 "rdnis=Unknown\n"
06063 "priority=%d\n"
06064 "callerchan=%s\n"
06065 "callerid=%s\n"
06066 "origdate=%s\n"
06067 "origtime=%ld\n"
06068 "category=%s\n"
06069 "msg_id=%s\n"
06070 "flag=\n"
06071 "duration=%d\n",
06072
06073 recdata->mailbox,
06074 S_OR(recdata->call_context, ""),
06075 S_OR(recdata->call_macrocontext, ""),
06076 S_OR(recdata->call_extension, ""),
06077 recdata->call_priority,
06078 S_OR(recdata->call_callerchan, "Unknown"),
06079 S_OR(recdata->call_callerid, "Unknown"),
06080 date, (long) time(NULL),
06081 S_OR(category, ""),
06082 msg_id,
06083 duration);
06084
06085
06086
06087 fclose(txt);
06088
06089 } else {
06090 ast_log(LOG_WARNING, "Error opening text file for output\n");
06091 if (ast_check_realtime("voicemail_data")) {
06092 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06093 }
06094 free_user(recipient);
06095 return -1;
06096 }
06097
06098
06099
06100
06101 create_dirpath(dir, sizeof(dir), recipient->context, recipient->mailbox, recdata->folder);
06102
06103 #ifdef IMAP_STORAGE
06104
06105 snprintf(ext_context, sizeof(ext_context), "%s@%s", recipient->mailbox, recipient->context);
06106
06107
06108
06109 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
06110 if (res < 0) {
06111 ast_log(LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
06112 free_user(recipient);
06113 unlink(tmptxtfile);
06114 return -1;
06115 }
06116 if (!(vms = get_vm_state_by_mailbox(recipient->mailbox, recipient->context, 0))) {
06117
06118
06119
06120
06121 if (!(vms = create_vm_state_from_user(recipient))) {
06122 ast_log(LOG_ERROR, "Couldn't allocate necessary space\n");
06123 free_user(recipient);
06124 unlink(tmptxtfile);
06125 return -1;
06126 }
06127 }
06128 vms->newmessages++;
06129
06130
06131 msgnum = newmsgs + oldmsgs;
06132 ast_debug(3, "Messagecount set to %d\n", msgnum);
06133 snprintf(destination, sizeof(destination), "%simap/msg%s%04d", VM_SPOOL_DIR, recipient->mailbox, msgnum);
06134
06135
06136
06137 if ((res = imap_check_limits(NULL, vms, recipient, msgnum))) {
06138 ast_log(LOG_NOTICE, "Didn't copy to voicemail. Mailbox for %s@%s is full.\n", recipient->mailbox, recipient->context);
06139 inprocess_count(recipient->mailbox, recipient->context, -1);
06140 free_user(recipient);
06141 unlink(tmptxtfile);
06142 return -1;
06143 }
06144
06145 #else
06146
06147
06148 ast_debug(3, "mailbox = %d : inprocess = %d\n", count_messages(recipient, dir),
06149 inprocess_count(recipient->mailbox, recipient->context, 0));
06150 if (count_messages(recipient, dir) > recipient->maxmsg - inprocess_count(recipient->mailbox, recipient->context, +1)) {
06151 ast_log(AST_LOG_WARNING, "Didn't copy to voicemail. Mailbox for %s@%s is full.\n", recipient->mailbox, recipient->context);
06152 inprocess_count(recipient->mailbox, recipient->context, -1);
06153 free_user(recipient);
06154 unlink(tmptxtfile);
06155 return -1;
06156 }
06157
06158 msgnum = last_message_index(recipient, dir) + 1;
06159 #endif
06160
06161
06162
06163 if (vm_lock_path(dir)) {
06164 ast_log(LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
06165
06166 ast_filedelete(tmptxtfile, NULL);
06167 unlink(tmptxtfile);
06168 free_user(recipient);
06169 return -1;
06170 }
06171
06172 make_file(destination, sizeof(destination), dir, msgnum);
06173
06174 make_file(tmpaudiofile, sizeof(tmpaudiofile), tmpdir, msgnum);
06175
06176 if (ast_filecopy(recdata->recording_file, tmpaudiofile, recdata->recording_ext)) {
06177 ast_log(LOG_ERROR, "Audio file failed to copy to tmp dir. Probably low disk space.\n");
06178
06179 inprocess_count(recipient->mailbox, recipient->context, -1);
06180 ast_unlock_path(dir);
06181 free_user(recipient);
06182 unlink(tmptxtfile);
06183 return -1;
06184 }
06185
06186
06187 if (ast_filerename(tmpaudiofile, destination, recdata->recording_ext)) {
06188 ast_log(LOG_ERROR, "Audio file failed to move to destination directory. Permissions/Overlap?\n");
06189 inprocess_count(recipient->mailbox, recipient->context, -1);
06190 ast_unlock_path(dir);
06191 free_user(recipient);
06192 unlink(tmptxtfile);
06193 return -1;
06194 }
06195
06196 snprintf(desttxtfile, sizeof(desttxtfile), "%s.txt", destination);
06197 rename(tmptxtfile, desttxtfile);
06198
06199 if (chmod(desttxtfile, VOICEMAIL_FILE_MODE) < 0) {
06200 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", desttxtfile, strerror(errno));
06201 }
06202
06203
06204 ast_unlock_path(dir);
06205 inprocess_count(recipient->mailbox, recipient->context, -1);
06206
06207
06208
06209
06210 if (ast_fileexists(destination, NULL, NULL) > 0) {
06211 if (ast_check_realtime("voicemail_data")) {
06212 get_date(date, sizeof(date));
06213 ast_store_realtime("voicemail_data",
06214 "origmailbox", recdata->mailbox,
06215 "context", S_OR(recdata->context, ""),
06216 "macrocontext", S_OR(recdata->call_macrocontext, ""),
06217 "exten", S_OR(recdata->call_extension, ""),
06218 "priority", recdata->call_priority,
06219 "callerchan", S_OR(recdata->call_callerchan, "Unknown"),
06220 "callerid", S_OR(recdata->call_callerid, "Unknown"),
06221 "origdate", date,
06222 "origtime", time(NULL),
06223 "category", S_OR(category, ""),
06224 "filename", tmptxtfile,
06225 "duration", duration,
06226 SENTINEL);
06227 }
06228
06229 STORE(dir, recipient->mailbox, recipient->context, msgnum, NULL, recipient, fmt, 0, vms, "", msg_id);
06230 }
06231
06232 free_user(recipient);
06233 unlink(tmptxtfile);
06234 return 0;
06235 }
06236
06237
06238
06239
06240
06241
06242
06243
06244
06245
06246
06247 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
06248 {
06249 #ifdef IMAP_STORAGE
06250 int newmsgs, oldmsgs;
06251 #else
06252 char urgdir[PATH_MAX];
06253 #endif
06254 char txtfile[PATH_MAX];
06255 char tmptxtfile[PATH_MAX];
06256 struct vm_state *vms = NULL;
06257 char callerid[256];
06258 FILE *txt;
06259 char date[256];
06260 int txtdes;
06261 int res = 0;
06262 int msgnum;
06263 int duration = 0;
06264 int sound_duration = 0;
06265 int ausemacro = 0;
06266 int ousemacro = 0;
06267 int ouseexten = 0;
06268 char tmpdur[16];
06269 char priority[16];
06270 char origtime[16];
06271 char dir[PATH_MAX];
06272 char tmpdir[PATH_MAX];
06273 char fn[PATH_MAX];
06274 char prefile[PATH_MAX] = "";
06275 char tempfile[PATH_MAX] = "";
06276 char ext_context[256] = "";
06277 char fmt[80];
06278 char *context;
06279 char ecodes[17] = "#";
06280 struct ast_str *tmp = ast_str_create(16);
06281 char *tmpptr;
06282 struct ast_vm_user *vmu;
06283 struct ast_vm_user svm;
06284 const char *category = NULL;
06285 const char *code;
06286 const char *alldtmf = "0123456789ABCD*#";
06287 char flag[80];
06288
06289 if (!tmp) {
06290 return -1;
06291 }
06292
06293 ast_str_set(&tmp, 0, "%s", ext);
06294 ext = ast_str_buffer(tmp);
06295 if ((context = strchr(ext, '@'))) {
06296 *context++ = '\0';
06297 tmpptr = strchr(context, '&');
06298 } else {
06299 tmpptr = strchr(ext, '&');
06300 }
06301
06302 if (tmpptr)
06303 *tmpptr++ = '\0';
06304
06305 ast_channel_lock(chan);
06306 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
06307 category = ast_strdupa(category);
06308 }
06309 ast_channel_unlock(chan);
06310
06311 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
06312 ast_copy_string(flag, "Urgent", sizeof(flag));
06313 } else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
06314 ast_copy_string(flag, "PRIORITY", sizeof(flag));
06315 } else {
06316 flag[0] = '\0';
06317 }
06318
06319 ast_debug(3, "Before find_user\n");
06320 if (!(vmu = find_user(&svm, context, ext))) {
06321 ast_log(AST_LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
06322 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06323 ast_free(tmp);
06324 return res;
06325 }
06326
06327 if (strcmp(vmu->context, "default"))
06328 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
06329 else
06330 ast_copy_string(ext_context, vmu->mailbox, sizeof(ext_context));
06331
06332
06333
06334
06335
06336
06337 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
06338 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
06339 } else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
06340 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
06341 }
06342
06343
06344
06345
06346 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
06347 if ((res = create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp"))) {
06348 ast_log(AST_LOG_WARNING, "Failed to make directory (%s)\n", tempfile);
06349 ast_free(tmp);
06350 return -1;
06351 }
06352 RETRIEVE(tempfile, -1, vmu->mailbox, vmu->context);
06353 if (ast_fileexists(tempfile, NULL, NULL) > 0)
06354 ast_copy_string(prefile, tempfile, sizeof(prefile));
06355
06356 DISPOSE(tempfile, -1);
06357
06358 #ifndef IMAP_STORAGE
06359 create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
06360 #else
06361 snprintf(dir, sizeof(dir), "%simap", VM_SPOOL_DIR);
06362 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
06363 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
06364 }
06365 #endif
06366
06367
06368 if (ast_test_flag(vmu, VM_OPERATOR)) {
06369 if (!ast_strlen_zero(vmu->exit)) {
06370 if (ast_exists_extension(chan, vmu->exit, "o", 1,
06371 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
06372 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
06373 ouseexten = 1;
06374 }
06375 } else if (ast_exists_extension(chan, ast_channel_context(chan), "o", 1,
06376 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
06377 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
06378 ouseexten = 1;
06379 } else if (!ast_strlen_zero(ast_channel_macrocontext(chan))
06380 && ast_exists_extension(chan, ast_channel_macrocontext(chan), "o", 1,
06381 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
06382 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
06383 ousemacro = 1;
06384 }
06385 }
06386
06387 if (!ast_strlen_zero(vmu->exit)) {
06388 if (ast_exists_extension(chan, vmu->exit, "a", 1,
06389 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
06390 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
06391 }
06392 } else if (ast_exists_extension(chan, ast_channel_context(chan), "a", 1,
06393 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
06394 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
06395 } else if (!ast_strlen_zero(ast_channel_macrocontext(chan))
06396 && ast_exists_extension(chan, ast_channel_macrocontext(chan), "a", 1,
06397 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
06398 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
06399 ausemacro = 1;
06400 }
06401
06402 if (ast_test_flag(options, OPT_DTMFEXIT)) {
06403 for (code = alldtmf; *code; code++) {
06404 char e[2] = "";
06405 e[0] = *code;
06406 if (strchr(ecodes, e[0]) == NULL
06407 && ast_canmatch_extension(chan,
06408 (!ast_strlen_zero(options->exitcontext) ? options->exitcontext : ast_channel_context(chan)),
06409 e, 1, S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
06410 strncat(ecodes, e, sizeof(ecodes) - strlen(ecodes) - 1);
06411 }
06412 }
06413 }
06414
06415
06416 if (!ast_strlen_zero(prefile)) {
06417 #ifdef ODBC_STORAGE
06418 int success =
06419 #endif
06420 RETRIEVE(prefile, -1, ext, context);
06421 if (ast_fileexists(prefile, NULL, NULL) > 0) {
06422 if (ast_streamfile(chan, prefile, ast_channel_language(chan)) > -1)
06423 res = ast_waitstream(chan, ecodes);
06424 #ifdef ODBC_STORAGE
06425 if (success == -1) {
06426
06427 ast_debug(1, "Greeting not retrieved from database, but found in file storage. Inserting into database\n");
06428 store_file(prefile, vmu->mailbox, vmu->context, -1);
06429 }
06430 #endif
06431 } else {
06432 ast_debug(1, "%s doesn't exist, doing what we can\n", prefile);
06433 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
06434 }
06435 DISPOSE(prefile, -1);
06436 if (res < 0) {
06437 ast_debug(1, "Hang up during prefile playback\n");
06438 free_user(vmu);
06439 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06440 ast_free(tmp);
06441 return -1;
06442 }
06443 }
06444 if (res == '#') {
06445
06446 ast_set_flag(options, OPT_SILENT);
06447 res = 0;
06448 }
06449
06450 if (vmu->maxmsg == 0) {
06451 ast_debug(3, "Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
06452 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06453 goto leave_vm_out;
06454 }
06455 if (!res && !ast_test_flag(options, OPT_SILENT)) {
06456 res = ast_stream_and_wait(chan, INTRO, ecodes);
06457 if (res == '#') {
06458 ast_set_flag(options, OPT_SILENT);
06459 res = 0;
06460 }
06461 }
06462 if (res > 0)
06463 ast_stopstream(chan);
06464
06465
06466 if (res == '*') {
06467 ast_channel_exten_set(chan, "a");
06468 if (!ast_strlen_zero(vmu->exit)) {
06469 ast_channel_context_set(chan, vmu->exit);
06470 } else if (ausemacro && !ast_strlen_zero(ast_channel_macrocontext(chan))) {
06471 ast_channel_context_set(chan, ast_channel_macrocontext(chan));
06472 }
06473 ast_channel_priority_set(chan, 0);
06474 free_user(vmu);
06475 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
06476 ast_free(tmp);
06477 return 0;
06478 }
06479
06480
06481 if (ast_test_flag(vmu, VM_OPERATOR) && res == '0') {
06482 transfer:
06483 if (ouseexten || ousemacro) {
06484 ast_channel_exten_set(chan, "o");
06485 if (!ast_strlen_zero(vmu->exit)) {
06486 ast_channel_context_set(chan, vmu->exit);
06487 } else if (ousemacro && !ast_strlen_zero(ast_channel_macrocontext(chan))) {
06488 ast_channel_context_set(chan, ast_channel_macrocontext(chan));
06489 }
06490 ast_play_and_wait(chan, "transfer");
06491 ast_channel_priority_set(chan, 0);
06492 free_user(vmu);
06493 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
06494 }
06495 ast_free(tmp);
06496 return OPERATOR_EXIT;
06497 }
06498
06499
06500 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
06501 if (!ast_strlen_zero(options->exitcontext)) {
06502 ast_channel_context_set(chan, options->exitcontext);
06503 }
06504 free_user(vmu);
06505 ast_free(tmp);
06506 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
06507 return res;
06508 }
06509
06510 if (res < 0) {
06511 free_user(vmu);
06512 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06513 ast_free(tmp);
06514 return -1;
06515 }
06516
06517 ast_copy_string(fmt, vmfmts, sizeof(fmt));
06518 if (!ast_strlen_zero(fmt)) {
06519 char msg_id[MSG_ID_LEN] = "";
06520 msgnum = 0;
06521
06522 #ifdef IMAP_STORAGE
06523
06524
06525 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
06526 if (res < 0) {
06527 ast_log(AST_LOG_NOTICE, "Can not leave voicemail, unable to count messages\n");
06528 ast_free(tmp);
06529 return -1;
06530 }
06531 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
06532
06533
06534
06535
06536 if (!(vms = create_vm_state_from_user(vmu))) {
06537 ast_log(AST_LOG_ERROR, "Couldn't allocate necessary space\n");
06538 ast_free(tmp);
06539 return -1;
06540 }
06541 }
06542 vms->newmessages++;
06543
06544
06545 msgnum = newmsgs + oldmsgs;
06546 ast_debug(3, "Messagecount set to %d\n", msgnum);
06547 snprintf(fn, sizeof(fn), "%simap/msg%s%04d", VM_SPOOL_DIR, vmu->mailbox, msgnum);
06548
06549 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06550
06551 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
06552 goto leave_vm_out;
06553 }
06554 #else
06555 if (count_messages(vmu, dir) >= vmu->maxmsg - inprocess_count(vmu->mailbox, vmu->context, +1)) {
06556 res = ast_streamfile(chan, "vm-mailboxfull", ast_channel_language(chan));
06557 if (!res)
06558 res = ast_waitstream(chan, "");
06559 ast_log(AST_LOG_WARNING, "No more messages possible\n");
06560 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06561 inprocess_count(vmu->mailbox, vmu->context, -1);
06562 goto leave_vm_out;
06563 }
06564
06565 #endif
06566 snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
06567 txtdes = mkstemp(tmptxtfile);
06568 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
06569 if (txtdes < 0) {
06570 res = ast_streamfile(chan, "vm-mailboxfull", ast_channel_language(chan));
06571 if (!res)
06572 res = ast_waitstream(chan, "");
06573 ast_log(AST_LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
06574 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06575 inprocess_count(vmu->mailbox, vmu->context, -1);
06576 goto leave_vm_out;
06577 }
06578
06579
06580 if (res >= 0) {
06581
06582 res = ast_stream_and_wait(chan, "beep", "");
06583 }
06584
06585
06586 if (ast_check_realtime("voicemail_data")) {
06587 snprintf(priority, sizeof(priority), "%d", ast_channel_priority(chan));
06588 snprintf(origtime, sizeof(origtime), "%ld", (long) time(NULL));
06589 get_date(date, sizeof(date));
06590 ast_callerid_merge(callerid, sizeof(callerid),
06591 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
06592 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
06593 "Unknown");
06594 ast_store_realtime("voicemail_data",
06595 "origmailbox", ext,
06596 "context", ast_channel_context(chan),
06597 "macrocontext", ast_channel_macrocontext(chan),
06598 "exten", ast_channel_exten(chan),
06599 "priority", priority,
06600 "callerchan", ast_channel_name(chan),
06601 "callerid", callerid,
06602 "origdate", date,
06603 "origtime", origtime,
06604 "category", S_OR(category, ""),
06605 "filename", tmptxtfile,
06606 SENTINEL);
06607 }
06608
06609
06610 txt = fdopen(txtdes, "w+");
06611 if (txt) {
06612 generate_msg_id(msg_id);
06613 get_date(date, sizeof(date));
06614 ast_callerid_merge(callerid, sizeof(callerid),
06615 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
06616 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
06617 "Unknown");
06618 fprintf(txt,
06619 ";\n"
06620 "; Message Information file\n"
06621 ";\n"
06622 "[message]\n"
06623 "origmailbox=%s\n"
06624 "context=%s\n"
06625 "macrocontext=%s\n"
06626 "exten=%s\n"
06627 "rdnis=%s\n"
06628 "priority=%d\n"
06629 "callerchan=%s\n"
06630 "callerid=%s\n"
06631 "origdate=%s\n"
06632 "origtime=%ld\n"
06633 "category=%s\n"
06634 "msg_id=%s\n",
06635 ext,
06636 ast_channel_context(chan),
06637 ast_channel_macrocontext(chan),
06638 ast_channel_exten(chan),
06639 S_COR(ast_channel_redirecting(chan)->from.number.valid,
06640 ast_channel_redirecting(chan)->from.number.str, "unknown"),
06641 ast_channel_priority(chan),
06642 ast_channel_name(chan),
06643 callerid,
06644 date, (long) time(NULL),
06645 category ? category : "",
06646 msg_id);
06647 } else {
06648 ast_log(AST_LOG_WARNING, "Error opening text file for output\n");
06649 inprocess_count(vmu->mailbox, vmu->context, -1);
06650 if (ast_check_realtime("voicemail_data")) {
06651 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06652 }
06653 res = ast_streamfile(chan, "vm-mailboxfull", ast_channel_language(chan));
06654 goto leave_vm_out;
06655 }
06656 res = play_record_review(chan, NULL, tmptxtfile, vmu->maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->record_gain, vms, flag, msg_id);
06657
06658 if (txt) {
06659 fprintf(txt, "flag=%s\n", flag);
06660 if (sound_duration < vmu->minsecs) {
06661 fclose(txt);
06662 ast_verb(3, "Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->minsecs);
06663 ast_filedelete(tmptxtfile, NULL);
06664 unlink(tmptxtfile);
06665 if (ast_check_realtime("voicemail_data")) {
06666 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06667 }
06668 inprocess_count(vmu->mailbox, vmu->context, -1);
06669 } else {
06670 fprintf(txt, "duration=%d\n", duration);
06671 fclose(txt);
06672 if (vm_lock_path(dir)) {
06673 ast_log(AST_LOG_ERROR, "Couldn't lock directory %s. Voicemail will be lost.\n", dir);
06674
06675 ast_filedelete(tmptxtfile, NULL);
06676 unlink(tmptxtfile);
06677 inprocess_count(vmu->mailbox, vmu->context, -1);
06678 } else if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
06679 ast_debug(1, "The recorded media file is gone, so we should remove the .txt file too!\n");
06680 unlink(tmptxtfile);
06681 ast_unlock_path(dir);
06682 inprocess_count(vmu->mailbox, vmu->context, -1);
06683 if (ast_check_realtime("voicemail_data")) {
06684 ast_destroy_realtime("voicemail_data", "filename", tmptxtfile, SENTINEL);
06685 }
06686 } else {
06687 #ifndef IMAP_STORAGE
06688 msgnum = last_message_index(vmu, dir) + 1;
06689 #endif
06690 make_file(fn, sizeof(fn), dir, msgnum);
06691
06692
06693 #ifndef IMAP_STORAGE
06694 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
06695 #else
06696 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", "IMAP_STORAGE");
06697 #endif
06698
06699 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
06700 ast_filerename(tmptxtfile, fn, NULL);
06701 rename(tmptxtfile, txtfile);
06702 inprocess_count(vmu->mailbox, vmu->context, -1);
06703
06704
06705
06706 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
06707 ast_log(AST_LOG_ERROR, "Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
06708
06709 ast_unlock_path(dir);
06710 if (ast_check_realtime("voicemail_data")) {
06711 snprintf(tmpdur, sizeof(tmpdur), "%d", duration);
06712 ast_update_realtime("voicemail_data", "filename", tmptxtfile, "filename", fn, "duration", tmpdur, SENTINEL);
06713 }
06714
06715
06716
06717 if (ast_fileexists(fn, NULL, NULL) > 0) {
06718 STORE(dir, vmu->mailbox, vmu->context, msgnum, chan, vmu, fmt, duration, vms, flag, msg_id);
06719 }
06720
06721
06722 while (tmpptr) {
06723 struct ast_vm_user recipu, *recip;
06724 char *exten, *cntx;
06725
06726 exten = strsep(&tmpptr, "&");
06727 cntx = strchr(exten, '@');
06728 if (cntx) {
06729 *cntx = '\0';
06730 cntx++;
06731 }
06732 if ((recip = find_user(&recipu, cntx, exten))) {
06733 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag, NULL);
06734 free_user(recip);
06735 }
06736 }
06737 #ifndef IMAP_STORAGE
06738 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
06739
06740 char sfn[PATH_MAX];
06741 char dfn[PATH_MAX];
06742 int x;
06743
06744 create_dirpath(urgdir, sizeof(urgdir), vmu->context, ext, "Urgent");
06745 x = last_message_index(vmu, urgdir) + 1;
06746 make_file(sfn, sizeof(sfn), dir, msgnum);
06747 make_file(dfn, sizeof(dfn), urgdir, x);
06748 ast_debug(5, "Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
06749 RENAME(dir, msgnum, vmu->mailbox, vmu->context, urgdir, x, sfn, dfn);
06750
06751 ast_copy_string(fn, dfn, sizeof(fn));
06752 msgnum = x;
06753 }
06754 #endif
06755
06756 if (ast_fileexists(fn, NULL, NULL)) {
06757 #ifdef IMAP_STORAGE
06758 notify_new_message(chan, vmu, vms, msgnum, duration, fmt,
06759 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
06760 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
06761 flag);
06762 #else
06763 notify_new_message(chan, vmu, NULL, msgnum, duration, fmt,
06764 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
06765 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
06766 flag);
06767 #endif
06768 }
06769
06770
06771 if (ast_fileexists(fn, NULL, NULL)) {
06772 DISPOSE(dir, msgnum);
06773 }
06774 }
06775 }
06776 } else {
06777 inprocess_count(vmu->mailbox, vmu->context, -1);
06778 }
06779 if (res == '0') {
06780 goto transfer;
06781 } else if (res > 0 && res != 't')
06782 res = 0;
06783
06784 if (sound_duration < vmu->minsecs)
06785
06786 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
06787 else
06788 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
06789 } else
06790 ast_log(AST_LOG_WARNING, "No format for saving voicemail?\n");
06791 leave_vm_out:
06792 free_user(vmu);
06793
06794 #ifdef IMAP_STORAGE
06795
06796 ast_debug(3, "*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
06797 if (expungeonhangup == 1) {
06798 ast_mutex_lock(&vms->lock);
06799 #ifdef HAVE_IMAP_TK2006
06800 if (LEVELUIDPLUS (vms->mailstream)) {
06801 mail_expunge_full(vms->mailstream, NIL, EX_UID);
06802 } else
06803 #endif
06804 mail_expunge(vms->mailstream);
06805 ast_mutex_unlock(&vms->lock);
06806 }
06807 #endif
06808
06809 ast_free(tmp);
06810 return res;
06811 }
06812
06813 #if !defined(IMAP_STORAGE)
06814 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
06815 {
06816
06817
06818 int x, dest;
06819 char sfn[PATH_MAX];
06820 char dfn[PATH_MAX];
06821
06822 if (vm_lock_path(dir)) {
06823 return ERROR_LOCK_PATH;
06824 }
06825
06826 for (x = 0, dest = 0; dest != stopcount && x < vmu->maxmsg + 10; x++) {
06827 make_file(sfn, sizeof(sfn), dir, x);
06828 if (EXISTS(dir, x, sfn, NULL)) {
06829
06830 if (x != dest) {
06831 make_file(dfn, sizeof(dfn), dir, dest);
06832 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
06833 }
06834
06835 dest++;
06836 }
06837 }
06838 ast_unlock_path(dir);
06839
06840 return dest;
06841 }
06842 #endif
06843
06844 static int say_and_wait(struct ast_channel *chan, int num, const char *language)
06845 {
06846 int d;
06847 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, NULL);
06848 return d;
06849 }
06850
06851 static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box, int *newmsg, int move)
06852 {
06853 #ifdef IMAP_STORAGE
06854
06855
06856 char sequence[10];
06857 char mailbox[256];
06858 int res;
06859
06860
06861 snprintf(sequence, sizeof(sequence), "%ld", vms->msgArray[msg]);
06862
06863 ast_debug(3, "Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
06864 ast_mutex_lock(&vms->lock);
06865
06866 if (box == OLD_FOLDER) {
06867 mail_setflag(vms->mailstream, sequence, "\\Seen");
06868 mail_clearflag(vms->mailstream, sequence, "\\Unseen");
06869 } else if (box == NEW_FOLDER) {
06870 mail_setflag(vms->mailstream, sequence, "\\Unseen");
06871 mail_clearflag(vms->mailstream, sequence, "\\Seen");
06872 }
06873 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
06874 ast_mutex_unlock(&vms->lock);
06875 return 0;
06876 }
06877
06878 imap_mailbox_name(mailbox, sizeof(mailbox), vms, box, 1);
06879 ast_debug(5, "Checking if folder exists: %s\n", mailbox);
06880 if (mail_create(vms->mailstream, mailbox) == NIL)
06881 ast_debug(5, "Folder exists.\n");
06882 else
06883 ast_log(AST_LOG_NOTICE, "Folder %s created!\n", mbox(vmu, box));
06884 if (move) {
06885 res = !mail_move(vms->mailstream, sequence, (char *) mbox(vmu, box));
06886 } else {
06887 res = !mail_copy(vms->mailstream, sequence, (char *) mbox(vmu, box));
06888 }
06889 ast_mutex_unlock(&vms->lock);
06890 return res;
06891 #else
06892 char *dir = vms->curdir;
06893 char *username = vms->username;
06894 char *context = vmu->context;
06895 char sfn[PATH_MAX];
06896 char dfn[PATH_MAX];
06897 char ddir[PATH_MAX];
06898 const char *dbox = mbox(vmu, box);
06899 int x, i;
06900 create_dirpath(ddir, sizeof(ddir), context, username, dbox);
06901
06902 if (vm_lock_path(ddir))
06903 return ERROR_LOCK_PATH;
06904
06905 x = last_message_index(vmu, ddir) + 1;
06906
06907 if (box == 10 && x >= vmu->maxdeletedmsg) {
06908 x--;
06909 for (i = 1; i <= x; i++) {
06910
06911 make_file(sfn, sizeof(sfn), ddir, i);
06912 make_file(dfn, sizeof(dfn), ddir, i - 1);
06913 if (EXISTS(ddir, i, sfn, NULL)) {
06914 RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn);
06915 } else
06916 break;
06917 }
06918 } else {
06919 if (x >= vmu->maxmsg) {
06920 ast_unlock_path(ddir);
06921 return -1;
06922 }
06923 }
06924 make_file(sfn, sizeof(sfn), dir, msg);
06925 make_file(dfn, sizeof(dfn), ddir, x);
06926 if (strcmp(sfn, dfn)) {
06927 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
06928 }
06929 ast_unlock_path(ddir);
06930
06931 if (newmsg) {
06932 *newmsg = x;
06933 }
06934 return 0;
06935 #endif
06936 }
06937
06938 static int adsi_logo(unsigned char *buf)
06939 {
06940 int bytes = 0;
06941 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
06942 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002-2006 Digium, Inc.", "");
06943 return bytes;
06944 }
06945
06946 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
06947 {
06948 unsigned char buf[256];
06949 int bytes = 0;
06950 int x;
06951 char num[5];
06952
06953 *useadsi = 0;
06954 bytes += ast_adsi_data_mode(buf + bytes);
06955 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06956
06957 bytes = 0;
06958 bytes += adsi_logo(buf);
06959 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06960 #ifdef DISPLAY
06961 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
06962 #endif
06963 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06964 bytes += ast_adsi_data_mode(buf + bytes);
06965 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06966
06967 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
06968 bytes = 0;
06969 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
06970 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
06971 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06972 bytes += ast_adsi_voice_mode(buf + bytes, 0);
06973 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06974 return 0;
06975 }
06976
06977 #ifdef DISPLAY
06978
06979 bytes = 0;
06980 bytes += ast_adsi_logo(buf);
06981 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
06982 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
06983 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
06984 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
06985 #endif
06986 bytes = 0;
06987 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
06988 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
06989 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
06990 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
06991 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
06992 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
06993 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
06994
06995 #ifdef DISPLAY
06996
06997 bytes = 0;
06998 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
06999 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07000
07001 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07002 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07003 #endif
07004
07005 bytes = 0;
07006
07007 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
07008 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
07009 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
07010 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
07011 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
07012 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
07013 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
07014
07015 #ifdef DISPLAY
07016
07017 bytes = 0;
07018 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
07019 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07020 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07021 #endif
07022
07023 bytes = 0;
07024 for (x = 0; x < 5; x++) {
07025 snprintf(num, sizeof(num), "%d", x);
07026 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
07027 }
07028 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
07029 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
07030
07031 #ifdef DISPLAY
07032
07033 bytes = 0;
07034 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
07035 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07036 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07037 #endif
07038
07039 if (ast_adsi_end_download(chan)) {
07040 bytes = 0;
07041 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
07042 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
07043 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07044 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07045 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07046 return 0;
07047 }
07048 bytes = 0;
07049 bytes += ast_adsi_download_disconnect(buf + bytes);
07050 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07051 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
07052
07053 ast_debug(1, "Done downloading scripts...\n");
07054
07055 #ifdef DISPLAY
07056
07057 bytes = 0;
07058 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
07059 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07060 #endif
07061 ast_debug(1, "Restarting session...\n");
07062
07063 bytes = 0;
07064
07065 if (ast_adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
07066 *useadsi = 1;
07067 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
07068 } else
07069 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
07070
07071 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07072 return 0;
07073 }
07074
07075 static void adsi_begin(struct ast_channel *chan, int *useadsi)
07076 {
07077 int x;
07078 if (!ast_adsi_available(chan))
07079 return;
07080 x = ast_adsi_load_session(chan, adsifdn, adsiver, 1);
07081 if (x < 0)
07082 return;
07083 if (!x) {
07084 if (adsi_load_vmail(chan, useadsi)) {
07085 ast_log(AST_LOG_WARNING, "Unable to upload voicemail scripts\n");
07086 return;
07087 }
07088 } else
07089 *useadsi = 1;
07090 }
07091
07092 static void adsi_login(struct ast_channel *chan)
07093 {
07094 unsigned char buf[256];
07095 int bytes = 0;
07096 unsigned char keys[8];
07097 int x;
07098 if (!ast_adsi_available(chan))
07099 return;
07100
07101 for (x = 0; x < 8; x++)
07102 keys[x] = 0;
07103
07104 keys[3] = ADSI_KEY_APPS + 3;
07105
07106 bytes += adsi_logo(buf + bytes);
07107 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
07108 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
07109 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07110 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
07111 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
07112 bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
07113 bytes += ast_adsi_set_keys(buf + bytes, keys);
07114 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07115 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07116 }
07117
07118 static void adsi_password(struct ast_channel *chan)
07119 {
07120 unsigned char buf[256];
07121 int bytes = 0;
07122 unsigned char keys[8];
07123 int x;
07124 if (!ast_adsi_available(chan))
07125 return;
07126
07127 for (x = 0; x < 8; x++)
07128 keys[x] = 0;
07129
07130 keys[3] = ADSI_KEY_APPS + 3;
07131
07132 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07133 bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
07134 bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
07135 bytes += ast_adsi_set_keys(buf + bytes, keys);
07136 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07137 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07138 }
07139
07140 static void adsi_folders(struct ast_channel *chan, int start, char *label)
07141 {
07142 unsigned char buf[256];
07143 int bytes = 0;
07144 unsigned char keys[8];
07145 int x, y;
07146
07147 if (!ast_adsi_available(chan))
07148 return;
07149
07150 for (x = 0; x < 5; x++) {
07151 y = ADSI_KEY_APPS + 12 + start + x;
07152 if (y > ADSI_KEY_APPS + 12 + 4)
07153 y = 0;
07154 keys[x] = ADSI_KEY_SKT | y;
07155 }
07156 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
07157 keys[6] = 0;
07158 keys[7] = 0;
07159
07160 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
07161 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
07162 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07163 bytes += ast_adsi_set_keys(buf + bytes, keys);
07164 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07165
07166 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07167 }
07168
07169 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
07170 {
07171 int bytes = 0;
07172 unsigned char buf[256];
07173 char buf1[256], buf2[256];
07174 char fn2[PATH_MAX];
07175
07176 char cid[256] = "";
07177 char *val;
07178 char *name, *num;
07179 char datetime[21] = "";
07180 FILE *f;
07181
07182 unsigned char keys[8];
07183
07184 int x;
07185
07186 if (!ast_adsi_available(chan))
07187 return;
07188
07189
07190 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
07191 f = fopen(fn2, "r");
07192 if (f) {
07193 while (!feof(f)) {
07194 if (!fgets((char *) buf, sizeof(buf), f)) {
07195 continue;
07196 }
07197 if (!feof(f)) {
07198 char *stringp = NULL;
07199 stringp = (char *) buf;
07200 strsep(&stringp, "=");
07201 val = strsep(&stringp, "=");
07202 if (!ast_strlen_zero(val)) {
07203 if (!strcmp((char *) buf, "callerid"))
07204 ast_copy_string(cid, val, sizeof(cid));
07205 if (!strcmp((char *) buf, "origdate"))
07206 ast_copy_string(datetime, val, sizeof(datetime));
07207 }
07208 }
07209 }
07210 fclose(f);
07211 }
07212
07213 for (x = 0; x < 5; x++)
07214 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
07215 keys[6] = 0x0;
07216 keys[7] = 0x0;
07217
07218 if (!vms->curmsg) {
07219
07220 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
07221 }
07222 if (vms->curmsg >= vms->lastmsg) {
07223
07224 if (vms->curmsg) {
07225
07226 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
07227 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07228
07229 } else {
07230
07231 keys[3] = 1;
07232 }
07233 }
07234
07235 if (!ast_strlen_zero(cid)) {
07236 ast_callerid_parse(cid, &name, &num);
07237 if (!name)
07238 name = num;
07239 } else {
07240 name = "Unknown Caller";
07241 }
07242
07243
07244 #ifdef IMAP_STORAGE
07245 ast_mutex_lock(&vms->lock);
07246 #endif
07247 if (vms->deleted[vms->curmsg]) {
07248 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
07249 }
07250 #ifdef IMAP_STORAGE
07251 ast_mutex_unlock(&vms->lock);
07252 #endif
07253
07254
07255 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
07256 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
07257 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
07258 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
07259
07260 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
07261 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
07262 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
07263 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
07264 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07265 bytes += ast_adsi_set_keys(buf + bytes, keys);
07266 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07267
07268 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07269 }
07270
07271 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
07272 {
07273 int bytes = 0;
07274 unsigned char buf[256];
07275 unsigned char keys[8];
07276
07277 int x;
07278
07279 if (!ast_adsi_available(chan))
07280 return;
07281
07282
07283 for (x = 0; x < 5; x++)
07284 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
07285
07286 keys[6] = 0x0;
07287 keys[7] = 0x0;
07288
07289 if (!vms->curmsg) {
07290
07291 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
07292 }
07293 if (vms->curmsg >= vms->lastmsg) {
07294
07295 if (vms->curmsg) {
07296
07297 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
07298 } else {
07299
07300 keys[3] = 1;
07301 }
07302 }
07303
07304
07305 #ifdef IMAP_STORAGE
07306 ast_mutex_lock(&vms->lock);
07307 #endif
07308 if (vms->deleted[vms->curmsg]) {
07309 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
07310 }
07311 #ifdef IMAP_STORAGE
07312 ast_mutex_unlock(&vms->lock);
07313 #endif
07314
07315
07316 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
07317 bytes += ast_adsi_set_keys(buf + bytes, keys);
07318 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07319
07320 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07321 }
07322
07323 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
07324 {
07325 unsigned char buf[256] = "";
07326 char buf1[256] = "", buf2[256] = "";
07327 int bytes = 0;
07328 unsigned char keys[8];
07329 int x;
07330
07331 char *newm = (vms->newmessages == 1) ? "message" : "messages";
07332 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
07333 if (!ast_adsi_available(chan))
07334 return;
07335 if (vms->newmessages) {
07336 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
07337 if (vms->oldmessages) {
07338 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
07339 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
07340 } else {
07341 snprintf(buf2, sizeof(buf2), "%s.", newm);
07342 }
07343 } else if (vms->oldmessages) {
07344 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
07345 snprintf(buf2, sizeof(buf2), "%s.", oldm);
07346 } else {
07347 strcpy(buf1, "You have no messages.");
07348 buf2[0] = ' ';
07349 buf2[1] = '\0';
07350 }
07351 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
07352 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
07353 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07354
07355 for (x = 0; x < 6; x++)
07356 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
07357 keys[6] = 0;
07358 keys[7] = 0;
07359
07360
07361 if (vms->lastmsg < 0)
07362 keys[0] = 1;
07363 bytes += ast_adsi_set_keys(buf + bytes, keys);
07364
07365 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07366
07367 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07368 }
07369
07370 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
07371 {
07372 unsigned char buf[256] = "";
07373 char buf1[256] = "", buf2[256] = "";
07374 int bytes = 0;
07375 unsigned char keys[8];
07376 int x;
07377
07378 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
07379
07380 if (!ast_adsi_available(chan))
07381 return;
07382
07383
07384 for (x = 0; x < 6; x++)
07385 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
07386
07387 keys[6] = 0;
07388 keys[7] = 0;
07389
07390 if ((vms->lastmsg + 1) < 1)
07391 keys[0] = 0;
07392
07393 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
07394 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
07395
07396 if (vms->lastmsg + 1)
07397 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
07398 else
07399 strcpy(buf2, "no messages.");
07400 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
07401 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
07402 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
07403 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07404 bytes += ast_adsi_set_keys(buf + bytes, keys);
07405
07406 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07407
07408 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07409
07410 }
07411
07412
07413
07414
07415
07416
07417
07418
07419
07420
07421
07422
07423
07424
07425
07426 static void adsi_goodbye(struct ast_channel *chan)
07427 {
07428 unsigned char buf[256];
07429 int bytes = 0;
07430
07431 if (!ast_adsi_available(chan))
07432 return;
07433 bytes += adsi_logo(buf + bytes);
07434 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
07435 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
07436 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
07437 bytes += ast_adsi_voice_mode(buf + bytes, 0);
07438
07439 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
07440 }
07441
07442
07443
07444
07445
07446 static int get_folder(struct ast_channel *chan, int start)
07447 {
07448 int x;
07449 int d;
07450 char fn[PATH_MAX];
07451 d = ast_play_and_wait(chan, "vm-press");
07452 if (d)
07453 return d;
07454 for (x = start; x < 5; x++) {
07455 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, ast_channel_language(chan), NULL)))
07456 return d;
07457 d = ast_play_and_wait(chan, "vm-for");
07458 if (d)
07459 return d;
07460 snprintf(fn, sizeof(fn), "vm-%s", mbox(NULL, x));
07461
07462
07463
07464
07465 if (x == 0) {
07466 if (ast_fileexists(fn, NULL, NULL)) {
07467 d = vm_play_folder_name(chan, fn);
07468 } else {
07469 ast_verb(1, "failed to find %s\n", fn);
07470 d = vm_play_folder_name(chan, "vm-INBOX");
07471 }
07472 } else {
07473 ast_test_suite_event_notify("PLAYBACK", "Message: folder name %s", fn);
07474 d = vm_play_folder_name(chan, fn);
07475 }
07476
07477 if (d)
07478 return d;
07479 d = ast_waitfordigit(chan, 500);
07480 if (d)
07481 return d;
07482 }
07483
07484 d = ast_play_and_wait(chan, "vm-tocancel");
07485 if (d)
07486 return d;
07487 d = ast_waitfordigit(chan, 4000);
07488 return d;
07489 }
07490
07491
07492
07493
07494
07495
07496
07497
07498
07499
07500
07501
07502
07503 static int get_folder2(struct ast_channel *chan, char *fn, int start)
07504 {
07505 int res = 0;
07506 int loops = 0;
07507
07508 res = ast_play_and_wait(chan, fn);
07509 while (((res < '0') || (res > '9')) &&
07510 (res != '#') && (res >= 0) &&
07511 loops < 4) {
07512 res = get_folder(chan, 0);
07513 loops++;
07514 }
07515 if (loops == 4) {
07516 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", '#', '#');
07517 return '#';
07518 }
07519 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
07520 return res;
07521 }
07522
07523
07524
07525
07526
07527
07528
07529
07530
07531
07532
07533
07534
07535
07536
07537
07538
07539
07540
07541 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts,
07542 char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
07543 {
07544 int cmd = 0;
07545 int retries = 0, prepend_duration = 0, already_recorded = 0;
07546 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07547 char textfile[PATH_MAX];
07548 struct ast_config *msg_cfg;
07549 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07550 #ifndef IMAP_STORAGE
07551 signed char zero_gain = 0;
07552 #else
07553 const char *msg_id = NULL;
07554 #endif
07555 const char *duration_str;
07556
07557
07558 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
07559 strcpy(textfile, msgfile);
07560 strcpy(backup, msgfile);
07561 strcpy(backup_textfile, msgfile);
07562 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
07563 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
07564 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
07565
07566 if ((msg_cfg = ast_config_load(textfile, config_flags)) && valid_config(msg_cfg) && (duration_str = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
07567 *duration = atoi(duration_str);
07568 } else {
07569 *duration = 0;
07570 }
07571
07572 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
07573 if (cmd)
07574 retries = 0;
07575 switch (cmd) {
07576 case '1':
07577
07578 #ifdef IMAP_STORAGE
07579
07580 if (msg_cfg && msg_cfg != CONFIG_STATUS_FILEINVALID) {
07581 msg_id = ast_variable_retrieve(msg_cfg, "message", "msg_id");
07582 }
07583 make_file(vms->introfn, sizeof(vms->introfn), curdir, curmsg);
07584 strncat(vms->introfn, "intro", sizeof(vms->introfn));
07585 ast_play_and_wait(chan, INTRO);
07586 ast_play_and_wait(chan, "beep");
07587 cmd = play_record_review(chan, NULL, vms->introfn, vmu->maxsecs, vm_fmts, 1, vmu, (int *) duration, NULL, NULL, record_gain, vms, flag, msg_id);
07588 if (cmd == -1) {
07589 break;
07590 }
07591 cmd = 't';
07592 #else
07593
07594
07595
07596 make_file(msgfile, sizeof(msgfile), curdir, curmsg);
07597 strcpy(textfile, msgfile);
07598 strncat(textfile, ".txt", sizeof(textfile) - 1);
07599 *duration = 0;
07600
07601
07602 if (!valid_config(msg_cfg)) {
07603 cmd = 0;
07604 break;
07605 }
07606
07607
07608 #ifndef IMAP_STORAGE
07609 if (already_recorded) {
07610 ast_filecopy(backup, msgfile, NULL);
07611 copy(backup_textfile, textfile);
07612 }
07613 else {
07614 ast_filecopy(msgfile, backup, NULL);
07615 copy(textfile, backup_textfile);
07616 }
07617 #endif
07618 already_recorded = 1;
07619
07620 if (record_gain)
07621 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
07622
07623 cmd = ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
07624
07625 if (cmd == 'S') {
07626 ast_stream_and_wait(chan, vm_pls_try_again, "");
07627 ast_stream_and_wait(chan, vm_prepend_timeout, "");
07628 ast_filerename(backup, msgfile, NULL);
07629 }
07630
07631 if (record_gain)
07632 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
07633
07634
07635 if ((duration_str = ast_variable_retrieve(msg_cfg, "message", "duration")))
07636 *duration = atoi(duration_str);
07637
07638 if (prepend_duration) {
07639 struct ast_category *msg_cat;
07640
07641 char duration_buf[12];
07642
07643 *duration += prepend_duration;
07644 msg_cat = ast_category_get(msg_cfg, "message");
07645 snprintf(duration_buf, 11, "%ld", *duration);
07646 if (!ast_variable_update(msg_cat, "duration", duration_buf, NULL, 0)) {
07647 ast_config_text_file_save(textfile, msg_cfg, "app_voicemail");
07648 }
07649 }
07650
07651 #endif
07652 break;
07653 case '2':
07654
07655 #ifdef IMAP_STORAGE
07656 *vms->introfn = '\0';
07657 #endif
07658 cmd = 't';
07659 break;
07660 case '*':
07661 cmd = '*';
07662 break;
07663 default:
07664
07665 already_recorded = 0;
07666
07667 cmd = ast_play_and_wait(chan, "vm-forwardoptions");
07668
07669 if (!cmd) {
07670 cmd = ast_play_and_wait(chan, "vm-starmain");
07671
07672 }
07673 if (!cmd) {
07674 cmd = ast_waitfordigit(chan, 6000);
07675 }
07676 if (!cmd) {
07677 retries++;
07678 }
07679 if (retries > 3) {
07680 cmd = '*';
07681 }
07682 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07683 }
07684 }
07685
07686 if (valid_config(msg_cfg))
07687 ast_config_destroy(msg_cfg);
07688 if (prepend_duration)
07689 *duration = prepend_duration;
07690
07691 if (already_recorded && cmd == -1) {
07692
07693 ast_filerename(backup, msgfile, NULL);
07694 rename(backup_textfile, textfile);
07695 }
07696
07697 if (cmd == 't' || cmd == 'S')
07698 cmd = 0;
07699 return cmd;
07700 }
07701
07702 static void queue_mwi_event(const char *box, int urgent, int new, int old)
07703 {
07704 struct ast_event *event;
07705 char *mailbox, *context;
07706
07707
07708 context = mailbox = ast_strdupa(box);
07709 strsep(&context, "@");
07710 if (ast_strlen_zero(context))
07711 context = "default";
07712
07713 if (!(event = ast_event_new(AST_EVENT_MWI,
07714 AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
07715 AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
07716 AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, (new+urgent),
07717 AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, old,
07718 AST_EVENT_IE_END))) {
07719 return;
07720 }
07721
07722 ast_event_queue_and_cache(event);
07723 }
07724
07725
07726
07727
07728
07729
07730
07731
07732
07733
07734
07735
07736
07737
07738
07739 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)
07740 {
07741 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
07742 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
07743 const char *category;
07744 char *myserveremail = serveremail;
07745
07746 ast_channel_lock(chan);
07747 if ((category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"))) {
07748 category = ast_strdupa(category);
07749 }
07750 ast_channel_unlock(chan);
07751
07752 #ifndef IMAP_STORAGE
07753 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, !ast_strlen_zero(flag) && !strcmp(flag, "Urgent") ? "Urgent" : "INBOX");
07754 #else
07755 snprintf(todir, sizeof(todir), "%simap", VM_SPOOL_DIR);
07756 #endif
07757 make_file(fn, sizeof(fn), todir, msgnum);
07758 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
07759
07760 if (!ast_strlen_zero(vmu->attachfmt)) {
07761 if (strstr(fmt, vmu->attachfmt))
07762 fmt = vmu->attachfmt;
07763 else
07764 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);
07765 }
07766
07767
07768 fmt = ast_strdupa(fmt);
07769 stringp = fmt;
07770 strsep(&stringp, "|");
07771
07772 if (!ast_strlen_zero(vmu->serveremail))
07773 myserveremail = vmu->serveremail;
07774
07775 if (!ast_strlen_zero(vmu->email)) {
07776 int attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
07777 char *msg_id = NULL;
07778 #ifdef IMAP_STORAGE
07779 struct ast_config *msg_cfg;
07780 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07781 char filename[PATH_MAX];
07782
07783 snprintf(filename, sizeof(filename), "%s.txt", fn);
07784 msg_cfg = ast_config_load(filename, config_flags);
07785 if (msg_cfg && msg_cfg != CONFIG_STATUS_FILEINVALID) {
07786 msg_id = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "msg_id"));
07787 ast_config_destroy(msg_cfg);
07788 }
07789 #endif
07790
07791 if (attach_user_voicemail)
07792 RETRIEVE(todir, msgnum, vmu->mailbox, vmu->context);
07793
07794
07795 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag, msg_id);
07796
07797 if (attach_user_voicemail)
07798 DISPOSE(todir, msgnum);
07799 }
07800
07801 if (!ast_strlen_zero(vmu->pager)) {
07802 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
07803 }
07804
07805 if (ast_test_flag(vmu, VM_DELETE))
07806 DELETE(todir, msgnum, fn, vmu);
07807
07808
07809 if (ast_app_has_voicemail(ext_context, NULL))
07810 ast_app_inboxcount2(ext_context, &urgentmsgs, &newmsgs, &oldmsgs);
07811
07812 queue_mwi_event(ext_context, urgentmsgs, newmsgs, oldmsgs);
07813
07814
07815
07816
07817
07818
07819
07820
07821
07822
07823
07824
07825
07826
07827
07828
07829
07830
07831
07832
07833 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting",
07834 "Mailbox: %s@%s\r\n"
07835 "Waiting: %d\r\n"
07836 "New: %d\r\n"
07837 "Old: %d\r\n", vmu->mailbox, vmu->context, ast_app_has_voicemail(ext_context, NULL), newmsgs, oldmsgs);
07838 run_externnotify(vmu->context, vmu->mailbox, flag);
07839
07840 #ifdef IMAP_STORAGE
07841 vm_delete(fn);
07842 if (ast_test_flag(vmu, VM_DELETE)) {
07843 vm_imap_delete(NULL, vms->curmsg, vmu);
07844 vms->newmessages--;
07845 }
07846 #endif
07847
07848 return 0;
07849 }
07850
07851
07852
07853
07854
07855
07856
07857
07858
07859
07860
07861
07862
07863
07864
07865
07866
07867
07868
07869
07870
07871
07872
07873
07874
07875
07876
07877
07878 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)
07879 {
07880 #ifdef IMAP_STORAGE
07881 int todircount = 0;
07882 struct vm_state *dstvms;
07883 #endif
07884 char username[70]="";
07885 char fn[PATH_MAX];
07886 char ecodes[16] = "#";
07887 int res = 0, cmd = 0;
07888 struct ast_vm_user *receiver = NULL, *vmtmp;
07889 AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
07890 char *stringp;
07891 const char *s;
07892 int saved_messages = 0;
07893 int valid_extensions = 0;
07894 char *dir;
07895 int curmsg;
07896 char urgent_str[7] = "";
07897 int prompt_played = 0;
07898 #ifndef IMAP_STORAGE
07899 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
07900 #endif
07901 if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
07902 ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
07903 }
07904
07905 if (vms == NULL) return -1;
07906 dir = vms->curdir;
07907 curmsg = vms->curmsg;
07908
07909 ast_test_suite_event_notify("FORWARD", "Message: entering forward message menu");
07910 while (!res && !valid_extensions) {
07911 int use_directory = 0;
07912 if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
07913 int done = 0;
07914 int retries = 0;
07915 cmd = 0;
07916 while ((cmd >= 0) && !done ){
07917 if (cmd)
07918 retries = 0;
07919 switch (cmd) {
07920 case '1':
07921 use_directory = 0;
07922 done = 1;
07923 break;
07924 case '2':
07925 use_directory = 1;
07926 done = 1;
07927 break;
07928 case '*':
07929 cmd = 't';
07930 done = 1;
07931 break;
07932 default:
07933
07934 cmd = ast_play_and_wait(chan, "vm-forward");
07935 if (!cmd) {
07936 cmd = ast_waitfordigit(chan, 3000);
07937 }
07938 if (!cmd) {
07939 retries++;
07940 }
07941 if (retries > 3) {
07942 cmd = 't';
07943 done = 1;
07944 }
07945 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
07946 }
07947 }
07948 if (cmd < 0 || cmd == 't')
07949 break;
07950 }
07951
07952 if (use_directory) {
07953
07954
07955 struct ast_app* directory_app;
07956
07957 directory_app = pbx_findapp("Directory");
07958 if (directory_app) {
07959 char vmcontext[256];
07960 char *old_context;
07961 char *old_exten;
07962 int old_priority;
07963
07964 old_context = ast_strdupa(ast_channel_context(chan));
07965 old_exten = ast_strdupa(ast_channel_exten(chan));
07966 old_priority = ast_channel_priority(chan);
07967
07968
07969 snprintf(vmcontext, sizeof(vmcontext), "%s,,v", context ? context : "default");
07970 res = pbx_exec(chan, directory_app, vmcontext);
07971
07972 ast_copy_string(username, ast_channel_exten(chan), sizeof(username));
07973
07974
07975 ast_channel_context_set(chan, old_context);
07976 ast_channel_exten_set(chan, old_exten);
07977 ast_channel_priority_set(chan, old_priority);
07978 } else {
07979 ast_log(AST_LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
07980 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
07981 }
07982 } else {
07983
07984 ast_test_suite_event_notify("PLAYBACK", "Message: vm-extension");
07985 res = ast_streamfile(chan, "vm-extension", ast_channel_language(chan));
07986 prompt_played++;
07987 if (res || prompt_played > 4)
07988 break;
07989 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#")) < 0)
07990 break;
07991 }
07992
07993
07994 if (ast_strlen_zero(username))
07995 continue;
07996 stringp = username;
07997 s = strsep(&stringp, "*");
07998
07999 valid_extensions = 1;
08000 while (s) {
08001 if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
08002 int oldmsgs;
08003 int newmsgs;
08004 int capacity;
08005 if (inboxcount(s, &newmsgs, &oldmsgs)) {
08006 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", s);
08007
08008 res = ast_play_and_wait(chan, "pbx-invalid");
08009 valid_extensions = 0;
08010 break;
08011 }
08012 capacity = receiver->maxmsg - inprocess_count(receiver->mailbox, receiver->context, +1);
08013 if ((newmsgs + oldmsgs) >= capacity) {
08014 ast_log(LOG_NOTICE, "Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
08015 res = ast_play_and_wait(chan, "vm-mailboxfull");
08016 valid_extensions = 0;
08017 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
08018 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
08019 free_user(vmtmp);
08020 }
08021 inprocess_count(receiver->mailbox, receiver->context, -1);
08022 break;
08023 }
08024 AST_LIST_INSERT_HEAD(&extensions, receiver, list);
08025 } else {
08026
08027
08028
08029
08030
08031 while ((receiver = AST_LIST_REMOVE_HEAD(&extensions, list))) {
08032 free_user(receiver);
08033 }
08034 ast_log(LOG_NOTICE, "'%s' is not a valid mailbox\n", s);
08035
08036 res = ast_play_and_wait(chan, "pbx-invalid");
08037 valid_extensions = 0;
08038 break;
08039 }
08040
08041
08042 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, receiver->context, s);
08043 RETRIEVE(fn, -1, s, receiver->context);
08044 if (ast_fileexists(fn, NULL, NULL) > 0) {
08045 res = ast_stream_and_wait(chan, fn, ecodes);
08046 if (res) {
08047 DISPOSE(fn, -1);
08048 return res;
08049 }
08050 } else {
08051 res = ast_say_digit_str(chan, s, ecodes, ast_channel_language(chan));
08052 }
08053 DISPOSE(fn, -1);
08054
08055 s = strsep(&stringp, "*");
08056 }
08057
08058 if (valid_extensions)
08059 break;
08060 }
08061
08062 if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
08063 return res;
08064 if (is_new_message == 1) {
08065 struct leave_vm_options leave_options;
08066 char mailbox[AST_MAX_EXTENSION * 2 + 2];
08067 snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
08068
08069
08070 memset(&leave_options, 0, sizeof(leave_options));
08071 leave_options.record_gain = record_gain;
08072 cmd = leave_voicemail(chan, mailbox, &leave_options);
08073 } else {
08074
08075 long duration = 0;
08076 struct vm_state vmstmp;
08077 int copy_msg_result = 0;
08078 #ifdef IMAP_STORAGE
08079 char filename[PATH_MAX];
08080 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
08081 const char *msg_id = NULL;
08082 struct ast_config *msg_cfg;
08083 #endif
08084 memcpy(&vmstmp, vms, sizeof(vmstmp));
08085
08086 RETRIEVE(dir, curmsg, sender->mailbox, sender->context);
08087 #ifdef IMAP_STORAGE
08088 make_file(filename, sizeof(filename), dir, curmsg);
08089 strncat(filename, ".txt", sizeof(filename) - strlen(filename) - 1);
08090 msg_cfg = ast_config_load(filename, config_flags);
08091 if (msg_cfg && msg_cfg == CONFIG_STATUS_FILEINVALID) {
08092 msg_id = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "msg_id"));
08093 ast_config_destroy(msg_cfg);
08094 }
08095 #endif
08096
08097 cmd = vm_forwardoptions(chan, sender, vmstmp.curdir, curmsg, vmfmts, S_OR(context, "default"), record_gain, &duration, &vmstmp, urgent_str);
08098 if (!cmd) {
08099 AST_LIST_TRAVERSE_SAFE_BEGIN(&extensions, vmtmp, list) {
08100 #ifdef IMAP_STORAGE
08101 int attach_user_voicemail;
08102 char *myserveremail = serveremail;
08103
08104
08105 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
08106 if (!dstvms) {
08107 dstvms = create_vm_state_from_user(vmtmp);
08108 }
08109 if (dstvms) {
08110 init_mailstream(dstvms, 0);
08111 if (!dstvms->mailstream) {
08112 ast_log(AST_LOG_ERROR, "IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
08113 } else {
08114 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, dstvms->curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str, msg_id);
08115 run_externnotify(vmtmp->context, vmtmp->mailbox, urgent_str);
08116 }
08117 } else {
08118 ast_log(AST_LOG_ERROR, "Could not find state information for mailbox %s\n", vmtmp->mailbox);
08119 }
08120 if (!ast_strlen_zero(vmtmp->serveremail))
08121 myserveremail = vmtmp->serveremail;
08122 attach_user_voicemail = ast_test_flag(vmtmp, VM_ATTACH);
08123
08124 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
08125 dstvms->curbox,
08126 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
08127 S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, NULL),
08128 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
08129 NULL, urgent_str, msg_id);
08130 #else
08131 copy_msg_result = copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str, NULL);
08132 #endif
08133 saved_messages++;
08134 AST_LIST_REMOVE_CURRENT(list);
08135 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
08136 free_user(vmtmp);
08137 if (res)
08138 break;
08139 }
08140 AST_LIST_TRAVERSE_SAFE_END;
08141 if (saved_messages > 0 && !copy_msg_result) {
08142
08143
08144
08145
08146
08147
08148
08149
08150 #ifdef IMAP_STORAGE
08151
08152 if (ast_strlen_zero(vmstmp.introfn))
08153 #endif
08154 res = ast_play_and_wait(chan, "vm-msgsaved");
08155 }
08156 #ifndef IMAP_STORAGE
08157 else {
08158
08159 res = ast_play_and_wait(chan, "vm-mailboxfull");
08160 }
08161
08162 make_file(msgfile, sizeof(msgfile), dir, curmsg);
08163 strcpy(textfile, msgfile);
08164 strcpy(backup, msgfile);
08165 strcpy(backup_textfile, msgfile);
08166 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
08167 strncat(backup, "-bak", sizeof(backup) - strlen(backup) - 1);
08168 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
08169 if (ast_fileexists(backup, NULL, NULL) > 0) {
08170 ast_filerename(backup, msgfile, NULL);
08171 rename(backup_textfile, textfile);
08172 }
08173 #endif
08174 }
08175 DISPOSE(dir, curmsg);
08176 #ifndef IMAP_STORAGE
08177 if (cmd) {
08178 make_file(msgfile, sizeof(msgfile), dir, curmsg);
08179 strcpy(textfile, msgfile);
08180 strcpy(backup_textfile, msgfile);
08181 strncat(textfile, ".txt", sizeof(textfile) - strlen(textfile) - 1);
08182 strncat(backup_textfile, "-bak.txt", sizeof(backup_textfile) - strlen(backup_textfile) - 1);
08183 rename(backup_textfile, textfile);
08184 }
08185 #endif
08186 }
08187
08188
08189 while ((vmtmp = AST_LIST_REMOVE_HEAD(&extensions, list))) {
08190 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
08191 free_user(vmtmp);
08192 }
08193 return res ? res : cmd;
08194 }
08195
08196 static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
08197 {
08198 int res;
08199 if ((res = ast_stream_and_wait(chan, file, AST_DIGIT_ANY)) < 0)
08200 ast_log(AST_LOG_WARNING, "Unable to play message %s\n", file);
08201 return res;
08202 }
08203
08204 static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
08205 {
08206 ast_test_suite_event_notify("PLAYVOICE", "Message: Playing %s", file);
08207 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);
08208 }
08209
08210 static int play_message_category(struct ast_channel *chan, const char *category)
08211 {
08212 int res = 0;
08213
08214 if (!ast_strlen_zero(category))
08215 res = ast_play_and_wait(chan, category);
08216
08217 if (res) {
08218 ast_log(AST_LOG_WARNING, "No sound file for category '%s' was found.\n", category);
08219 res = 0;
08220 }
08221
08222 return res;
08223 }
08224
08225 static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
08226 {
08227 int res = 0;
08228 struct vm_zone *the_zone = NULL;
08229 time_t t;
08230
08231 if (ast_get_time_t(origtime, &t, 0, NULL)) {
08232 ast_log(AST_LOG_WARNING, "Couldn't find origtime in %s\n", filename);
08233 return 0;
08234 }
08235
08236
08237 if (!ast_strlen_zero(vmu->zonetag)) {
08238
08239 struct vm_zone *z;
08240 AST_LIST_LOCK(&zones);
08241 AST_LIST_TRAVERSE(&zones, z, list) {
08242 if (!strcmp(z->name, vmu->zonetag)) {
08243 the_zone = z;
08244 break;
08245 }
08246 }
08247 AST_LIST_UNLOCK(&zones);
08248 }
08249
08250
08251 #if 0
08252
08253 ast_localtime(&t, &time_now, NULL);
08254 tv_now = ast_tvnow();
08255 ast_localtime(&tv_now, &time_then, NULL);
08256
08257
08258 if (time_now.tm_year == time_then.tm_year)
08259 snprintf(temp, sizeof(temp), "%d", time_now.tm_yday);
08260 else
08261 snprintf(temp, sizeof(temp), "%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
08262 pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp);
08263
08264
08265 #endif
08266 if (the_zone) {
08267 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), the_zone->msg_format, the_zone->timezone);
08268 } else if (!strncasecmp(ast_channel_language(chan), "de", 2)) {
08269 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL);
08270 } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) {
08271 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q H 'digits/kai' M ", NULL);
08272 } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) {
08273 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q 'digits/at' 'digits/hours' k 'digits/e' M 'digits/minutes'", NULL);
08274 } else if (!strncasecmp(ast_channel_language(chan), "nl", 2)) {
08275 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q 'digits/nl-om' HM", NULL);
08276 } else if (!strncasecmp(ast_channel_language(chan), "no", 2)) {
08277 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q 'digits/at' HM", NULL);
08278 } else if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
08279 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Q HM", NULL);
08280 } else if (!strncasecmp(ast_channel_language(chan), "pt_BR", 5)) {
08281 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' Ad 'digits/pt-de' B 'digits/pt-de' Y 'digits/pt-as' HM ", NULL);
08282 } else if (!strncasecmp(ast_channel_language(chan), "se", 2)) {
08283 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' dB 'digits/at' k 'and' M", NULL);
08284 } else if (!strncasecmp(ast_channel_language(chan), "zh", 2)) {
08285 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "qR 'vm-received'", NULL);
08286 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {
08287 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' A 'digits/day' dB 'digits/year' Y 'digits/at' k 'hours' M 'minutes'", NULL);
08288 } else {
08289 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), "'vm-received' q 'digits/at' IMp", NULL);
08290 }
08291 #if 0
08292 pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL);
08293 #endif
08294 return res;
08295 }
08296
08297
08298
08299 static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback, int saycidnumber)
08300 {
08301 int res = 0;
08302 int i;
08303 char *callerid, *name;
08304 char prefile[PATH_MAX] = "";
08305
08306
08307
08308
08309
08310
08311
08312
08313 if ((cid == NULL)||(context == NULL))
08314 return res;
08315
08316
08317 ast_debug(1, "VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
08318 ast_callerid_parse(cid, &name, &callerid);
08319 if ((!ast_strlen_zero(callerid)) && strcmp(callerid, "Unknown")) {
08320
08321
08322 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
08323 ast_debug(1, "VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
08324 if ((strcmp(cidinternalcontexts[i], context) == 0))
08325 break;
08326 }
08327 if (i != MAX_NUM_CID_CONTEXTS){
08328 if (!res) {
08329 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
08330 if (!ast_strlen_zero(prefile)) {
08331
08332
08333 if (ast_fileexists(prefile, NULL, NULL) > 0) {
08334 ast_verb(3, "Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
08335 if (!callback)
08336 res = wait_file2(chan, vms, "vm-from");
08337 res = ast_stream_and_wait(chan, prefile, "");
08338 } else {
08339 ast_verb(3, "Playing envelope info: message from '%s'\n", callerid);
08340
08341 if (!callback)
08342 res = wait_file2(chan, vms, "vm-from-extension");
08343 res = ast_say_digit_str(chan, callerid, "", ast_channel_language(chan));
08344 }
08345 }
08346 }
08347 } else if (!res) {
08348 ast_debug(1, "VM-CID: Numeric caller id: (%s)\n", callerid);
08349
08350 if (!callback) {
08351
08352 snprintf(prefile, sizeof(prefile), "%s/recordings/callerids/%s", ast_config_AST_SPOOL_DIR, callerid);
08353 if (!saycidnumber && ast_fileexists(prefile, NULL, NULL) > 0) {
08354 ast_verb(3, "Playing recorded name for CID number '%s' - '%s'\n", callerid,prefile);
08355 wait_file2(chan, vms, "vm-from");
08356 res = ast_stream_and_wait(chan, prefile, "");
08357 ast_verb(3, "Played recorded name result '%d'\n", res);
08358 } else {
08359
08360 wait_file2(chan, vms, "vm-from-phonenumber");
08361 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, ast_channel_language(chan));
08362 }
08363 } else {
08364 res = ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, ast_channel_language(chan));
08365 }
08366 }
08367 } else {
08368
08369 ast_debug(1, "VM-CID: From an unknown number\n");
08370
08371 res = wait_file2(chan, vms, "vm-unknown-caller");
08372 }
08373 return res;
08374 }
08375
08376 static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
08377 {
08378 int res = 0;
08379 int durationm;
08380 int durations;
08381
08382 if (duration == NULL)
08383 return res;
08384
08385
08386 durations = atoi(duration);
08387 durationm = (durations / 60);
08388
08389 ast_debug(1, "VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
08390
08391 if ((!res) && (durationm >= minduration)) {
08392 res = wait_file2(chan, vms, "vm-duration");
08393
08394
08395 if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
08396 div_t num = div(durationm, 10);
08397
08398 if (durationm == 1) {
08399 res = ast_play_and_wait(chan, "digits/1z");
08400 res = res ? res : ast_play_and_wait(chan, "vm-minute-ta");
08401 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
08402 if (num.rem == 2) {
08403 if (!num.quot) {
08404 res = ast_play_and_wait(chan, "digits/2-ie");
08405 } else {
08406 res = say_and_wait(chan, durationm - 2 , ast_channel_language(chan));
08407 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
08408 }
08409 } else {
08410 res = say_and_wait(chan, durationm, ast_channel_language(chan));
08411 }
08412 res = res ? res : ast_play_and_wait(chan, "vm-minute-ty");
08413 } else {
08414 res = say_and_wait(chan, durationm, ast_channel_language(chan));
08415 res = res ? res : ast_play_and_wait(chan, "vm-minute-t");
08416 }
08417
08418 } else {
08419 res = ast_say_number(chan, durationm, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
08420 res = wait_file2(chan, vms, "vm-minutes");
08421 }
08422 }
08423 return res;
08424 }
08425
08426 static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
08427 {
08428 int res = 0;
08429 char filename[256], *cid;
08430 const char *origtime, *context, *category, *duration, *flag;
08431 struct ast_config *msg_cfg;
08432 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
08433
08434 vms->starting = 0;
08435 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
08436 adsi_message(chan, vms);
08437 if (!vms->curmsg) {
08438 res = wait_file2(chan, vms, "vm-first");
08439 } else if (vms->curmsg == vms->lastmsg) {
08440 res = wait_file2(chan, vms, "vm-last");
08441 }
08442
08443 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
08444 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
08445 msg_cfg = ast_config_load(filename, config_flags);
08446 if (!valid_config(msg_cfg)) {
08447 ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
08448 return 0;
08449 }
08450 flag = ast_variable_retrieve(msg_cfg, "message", "flag");
08451
08452
08453 if (!ast_strlen_zero(flag) && !strcmp(flag, "Urgent")) {
08454 res = wait_file2(chan, vms, "vm-Urgent");
08455 }
08456
08457 if (!res) {
08458
08459
08460 if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
08461 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
08462 int ten, one;
08463 char nextmsg[256];
08464 ten = (vms->curmsg + 1) / 10;
08465 one = (vms->curmsg + 1) % 10;
08466
08467 if (vms->curmsg < 20) {
08468 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", vms->curmsg + 1);
08469 res = wait_file2(chan, vms, nextmsg);
08470 } else {
08471 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", ten * 10);
08472 res = wait_file2(chan, vms, nextmsg);
08473 if (one > 0) {
08474 if (!res) {
08475 snprintf(nextmsg, sizeof(nextmsg), "digits/n-%d", one);
08476 res = wait_file2(chan, vms, nextmsg);
08477 }
08478 }
08479 }
08480 }
08481 if (!res)
08482 res = wait_file2(chan, vms, "vm-message");
08483
08484 } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) {
08485 if (!vms->curmsg) {
08486 res = wait_file2(chan, vms, "vm-message");
08487 res = wait_file2(chan, vms, "vm-first");
08488 } else if (vms->curmsg == vms->lastmsg) {
08489 res = wait_file2(chan, vms, "vm-message");
08490 res = wait_file2(chan, vms, "vm-last");
08491 } else {
08492 res = wait_file2(chan, vms, "vm-message");
08493 res = wait_file2(chan, vms, "vm-number");
08494 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), "f");
08495 }
08496
08497 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {
08498 if (!vms->curmsg) {
08499 res = wait_file2(chan, vms, "vm-message");
08500 res = wait_file2(chan, vms, "vm-first");
08501 } else if (vms->curmsg == vms->lastmsg) {
08502 res = wait_file2(chan, vms, "vm-message");
08503 res = wait_file2(chan, vms, "vm-last");
08504 } else {
08505 res = wait_file2(chan, vms, "vm-message");
08506 res = wait_file2(chan, vms, "vm-number");
08507 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), "f");
08508 }
08509 } else {
08510 if (!strncasecmp(ast_channel_language(chan), "se", 2)) {
08511 res = wait_file2(chan, vms, "vm-meddelandet");
08512 } else {
08513 res = wait_file2(chan, vms, "vm-message");
08514 }
08515 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
08516 if (!res) {
08517 ast_test_suite_event_notify("PLAYBACK", "Message: message number");
08518 res = ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
08519 }
08520 }
08521 }
08522 }
08523
08524 if (!valid_config(msg_cfg)) {
08525 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
08526 return 0;
08527 }
08528
08529 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
08530 ast_log(AST_LOG_WARNING, "No origtime?!\n");
08531 DISPOSE(vms->curdir, vms->curmsg);
08532 ast_config_destroy(msg_cfg);
08533 return 0;
08534 }
08535
08536 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
08537 duration = ast_variable_retrieve(msg_cfg, "message", "duration");
08538 category = ast_variable_retrieve(msg_cfg, "message", "category");
08539
08540 context = ast_variable_retrieve(msg_cfg, "message", "context");
08541 if (!strncasecmp("macro", context, 5))
08542 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
08543 if (!res) {
08544 res = play_message_category(chan, category);
08545 }
08546 if ((!res) && (ast_test_flag(vmu, VM_ENVELOPE))) {
08547 res = play_message_datetime(chan, vmu, origtime, filename);
08548 }
08549 if ((!res) && (ast_test_flag(vmu, VM_SAYCID))) {
08550 res = play_message_callerid(chan, vms, cid, context, 0, 0);
08551 }
08552 if ((!res) && (ast_test_flag(vmu, VM_SAYDURATION))) {
08553 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
08554 }
08555
08556 if (res == '1') {
08557 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
08558 res = 0;
08559 }
08560 ast_config_destroy(msg_cfg);
08561
08562 if (!res) {
08563 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
08564 #ifdef IMAP_STORAGE
08565 ast_mutex_lock(&vms->lock);
08566 #endif
08567 vms->heard[vms->curmsg] = 1;
08568 #ifdef IMAP_STORAGE
08569 ast_mutex_unlock(&vms->lock);
08570
08571
08572
08573 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
08574 wait_file(chan, vms, vms->introfn);
08575 }
08576 #endif
08577 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
08578 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
08579 res = 0;
08580 }
08581 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
08582 }
08583 DISPOSE(vms->curdir, vms->curmsg);
08584 return res;
08585 }
08586
08587 #ifdef IMAP_STORAGE
08588 static int imap_remove_file(char *dir, int msgnum)
08589 {
08590 char fn[PATH_MAX];
08591 char full_fn[PATH_MAX];
08592 char intro[PATH_MAX] = {0,};
08593
08594 if (msgnum > -1) {
08595 make_file(fn, sizeof(fn), dir, msgnum);
08596 snprintf(intro, sizeof(intro), "%sintro", fn);
08597 } else
08598 ast_copy_string(fn, dir, sizeof(fn));
08599
08600 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
08601 ast_filedelete(fn, NULL);
08602 if (!ast_strlen_zero(intro)) {
08603 ast_filedelete(intro, NULL);
08604 }
08605 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
08606 unlink(full_fn);
08607 }
08608 return 0;
08609 }
08610
08611
08612
08613 static int imap_delete_old_greeting (char *dir, struct vm_state *vms)
08614 {
08615 char *file, *filename;
08616 char *attachment;
08617 char arg[10];
08618 int i;
08619 BODY* body;
08620
08621 file = strrchr(ast_strdupa(dir), '/');
08622 if (file) {
08623 *file++ = '\0';
08624 } else {
08625 ast_log(AST_LOG_ERROR, "Failed to procure file name from directory passed. You should never see this.\n");
08626 return -1;
08627 }
08628
08629 ast_mutex_lock(&vms->lock);
08630 for (i = 0; i < vms->mailstream->nmsgs; i++) {
08631 mail_fetchstructure(vms->mailstream, i + 1, &body);
08632
08633 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
08634 attachment = ast_strdupa(body->nested.part->next->body.parameter->value);
08635 } else {
08636 ast_log(AST_LOG_ERROR, "There is no file attached to this IMAP message.\n");
08637 ast_mutex_unlock(&vms->lock);
08638 return -1;
08639 }
08640 filename = strsep(&attachment, ".");
08641 if (!strcmp(filename, file)) {
08642 sprintf(arg, "%d", i + 1);
08643 mail_setflag(vms->mailstream, arg, "\\DELETED");
08644 }
08645 }
08646 mail_expunge(vms->mailstream);
08647 ast_mutex_unlock(&vms->lock);
08648 return 0;
08649 }
08650
08651 #elif !defined(IMAP_STORAGE)
08652 static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
08653 {
08654 int count_msg, last_msg;
08655
08656 ast_copy_string(vms->curbox, mbox(vmu, box), sizeof(vms->curbox));
08657
08658
08659
08660
08661 snprintf(vms->vmbox, sizeof(vms->vmbox), "vm-%s", vms->curbox);
08662
08663
08664 create_dirpath(vms->curdir, sizeof(vms->curdir), vmu->context, vms->username, vms->curbox);
08665
08666
08667 count_msg = count_messages(vmu, vms->curdir);
08668 if (count_msg < 0) {
08669 return count_msg;
08670 } else {
08671 vms->lastmsg = count_msg - 1;
08672 }
08673
08674 if (vm_allocate_dh(vms, vmu, count_msg)) {
08675 return -1;
08676 }
08677
08678
08679
08680
08681
08682
08683
08684
08685 if (vm_lock_path(vms->curdir)) {
08686 ast_log(AST_LOG_ERROR, "Could not open mailbox %s: mailbox is locked\n", vms->curdir);
08687 return ERROR_LOCK_PATH;
08688 }
08689
08690
08691 last_msg = last_message_index(vmu, vms->curdir);
08692 ast_unlock_path(vms->curdir);
08693
08694 if (last_msg < -1) {
08695 return last_msg;
08696 } else if (vms->lastmsg != last_msg) {
08697 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);
08698 resequence_mailbox(vmu, vms->curdir, count_msg);
08699 }
08700
08701 return 0;
08702 }
08703 #endif
08704
08705 static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
08706 {
08707 int x = 0;
08708 int last_msg_idx = 0;
08709
08710 #ifndef IMAP_STORAGE
08711 int res = 0, nummsg;
08712 char fn2[PATH_MAX];
08713 #endif
08714
08715 if (vms->lastmsg <= -1) {
08716 goto done;
08717 }
08718
08719 vms->curmsg = -1;
08720 #ifndef IMAP_STORAGE
08721
08722 if (vm_lock_path(vms->curdir)) {
08723 return ERROR_LOCK_PATH;
08724 }
08725
08726
08727 last_msg_idx = last_message_index(vmu, vms->curdir);
08728 if (last_msg_idx != vms->lastmsg) {
08729 ast_log(AST_LOG_NOTICE, "%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
08730 }
08731
08732
08733 for (x = 0; x < last_msg_idx + 1; x++) {
08734 if (!vms->deleted[x] && ((strcasecmp(vms->curbox, "INBOX") && strcasecmp(vms->curbox, "Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu, VM_MOVEHEARD)))) {
08735
08736 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08737 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
08738 break;
08739 }
08740 vms->curmsg++;
08741 make_file(fn2, sizeof(fn2), vms->curdir, vms->curmsg);
08742 if (strcmp(vms->fn, fn2)) {
08743 RENAME(vms->curdir, x, vmu->mailbox, vmu->context, vms->curdir, vms->curmsg, vms->fn, fn2);
08744 }
08745 } else if ((!strcasecmp(vms->curbox, "INBOX") || !strcasecmp(vms->curbox, "Urgent")) && vms->heard[x] && ast_test_flag(vmu, VM_MOVEHEARD) && !vms->deleted[x]) {
08746
08747 res = save_to_folder(vmu, vms, x, 1, NULL, 0);
08748 if (res == ERROR_LOCK_PATH) {
08749
08750 ast_log(AST_LOG_WARNING, "Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ? "unable to lock path" : "destination folder full");
08751 vms->deleted[x] = 0;
08752 vms->heard[x] = 0;
08753 --x;
08754 }
08755 } else if (vms->deleted[x] && vmu->maxdeletedmsg) {
08756
08757 res = save_to_folder(vmu, vms, x, 10, NULL, 0);
08758 if (res == ERROR_LOCK_PATH) {
08759
08760 vms->deleted[x] = 0;
08761 vms->heard[x] = 0;
08762 --x;
08763 }
08764 } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) {
08765
08766
08767 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08768 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08769 DELETE(vms->curdir, x, vms->fn, vmu);
08770 }
08771 }
08772 }
08773
08774
08775 nummsg = x - 1;
08776 for (x = vms->curmsg + 1; x <= nummsg; x++) {
08777 make_file(vms->fn, sizeof(vms->fn), vms->curdir, x);
08778 if (EXISTS(vms->curdir, x, vms->fn, NULL)) {
08779 DELETE(vms->curdir, x, vms->fn, vmu);
08780 }
08781 }
08782 ast_unlock_path(vms->curdir);
08783 #else
08784 ast_mutex_lock(&vms->lock);
08785 if (vms->deleted) {
08786
08787
08788 last_msg_idx = vms->dh_arraysize;
08789 for (x = last_msg_idx - 1; x >= 0; x--) {
08790 if (vms->deleted[x]) {
08791 ast_debug(3, "IMAP delete of %d\n", x);
08792 DELETE(vms->curdir, x, vms->fn, vmu);
08793 }
08794 }
08795 }
08796 #endif
08797
08798 done:
08799 if (vms->deleted) {
08800 ast_free(vms->deleted);
08801 vms->deleted = NULL;
08802 }
08803 if (vms->heard) {
08804 ast_free(vms->heard);
08805 vms->heard = NULL;
08806 }
08807 vms->dh_arraysize = 0;
08808 #ifdef IMAP_STORAGE
08809 ast_mutex_unlock(&vms->lock);
08810 #endif
08811
08812 return 0;
08813 }
08814
08815
08816
08817
08818
08819
08820
08821 static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
08822 {
08823 int cmd;
08824 char *buf;
08825
08826 buf = ast_alloca(strlen(box) + 2);
08827 strcpy(buf, box);
08828 strcat(buf, "s");
08829
08830 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")){
08831 cmd = ast_play_and_wait(chan, buf);
08832 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08833 } else {
08834 cmd = ast_play_and_wait(chan, "vm-messages");
08835 return cmd ? cmd : ast_play_and_wait(chan, box);
08836 }
08837 }
08838
08839 static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
08840 {
08841 int cmd;
08842
08843 if (!strcasecmp(box, "vm-INBOX") || !strcasecmp(box, "vm-Old")) {
08844 if (!strcasecmp(box, "vm-INBOX"))
08845 cmd = ast_play_and_wait(chan, "vm-new-e");
08846 else
08847 cmd = ast_play_and_wait(chan, "vm-old-e");
08848 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08849 } else {
08850 cmd = ast_play_and_wait(chan, "vm-messages");
08851 return cmd ? cmd : ast_play_and_wait(chan, box);
08852 }
08853 }
08854
08855 static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
08856 {
08857 int cmd;
08858
08859 if (!strcasecmp(box, "vm-Family") || !strcasecmp(box, "vm-Friends") || !strcasecmp(box, "vm-Work")){
08860 cmd = ast_play_and_wait(chan, "vm-messages");
08861 return cmd ? cmd : ast_play_and_wait(chan, box);
08862 } else {
08863 cmd = ast_play_and_wait(chan, box);
08864 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08865 }
08866 }
08867
08868 static int vm_play_folder_name(struct ast_channel *chan, char *box)
08869 {
08870 int cmd;
08871
08872 if ( !strncasecmp(ast_channel_language(chan), "it", 2) ||
08873 !strncasecmp(ast_channel_language(chan), "es", 2) ||
08874 !strncasecmp(ast_channel_language(chan), "pt", 2)) {
08875 cmd = ast_play_and_wait(chan, "vm-messages");
08876 return cmd ? cmd : ast_play_and_wait(chan, box);
08877 } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) {
08878 return vm_play_folder_name_gr(chan, box);
08879 } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) {
08880 return ast_play_and_wait(chan, box);
08881 } else if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
08882 return vm_play_folder_name_pl(chan, box);
08883 } else if (!strncasecmp(ast_channel_language(chan), "ua", 2)) {
08884 return vm_play_folder_name_ua(chan, box);
08885 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {
08886 return ast_play_and_wait(chan, box);
08887 } else {
08888 cmd = ast_play_and_wait(chan, box);
08889 return cmd ? cmd : ast_play_and_wait(chan, "vm-messages");
08890 }
08891 }
08892
08893
08894
08895
08896
08897
08898
08899
08900
08901
08902
08903
08904
08905 static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
08906 {
08907 int res = 0;
08908
08909 if (vms->newmessages) {
08910 res = ast_play_and_wait(chan, "vm-youhave");
08911 if (!res)
08912 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
08913 if (!res) {
08914 if ((vms->newmessages == 1)) {
08915 res = ast_play_and_wait(chan, "vm-INBOX");
08916 if (!res)
08917 res = ast_play_and_wait(chan, "vm-message");
08918 } else {
08919 res = ast_play_and_wait(chan, "vm-INBOXs");
08920 if (!res)
08921 res = ast_play_and_wait(chan, "vm-messages");
08922 }
08923 }
08924 } else if (vms->oldmessages){
08925 res = ast_play_and_wait(chan, "vm-youhave");
08926 if (!res)
08927 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
08928 if ((vms->oldmessages == 1)){
08929 res = ast_play_and_wait(chan, "vm-Old");
08930 if (!res)
08931 res = ast_play_and_wait(chan, "vm-message");
08932 } else {
08933 res = ast_play_and_wait(chan, "vm-Olds");
08934 if (!res)
08935 res = ast_play_and_wait(chan, "vm-messages");
08936 }
08937 } else if (!vms->oldmessages && !vms->newmessages)
08938 res = ast_play_and_wait(chan, "vm-denExeteMynhmata");
08939 return res;
08940 }
08941
08942
08943
08944
08945
08946
08947
08948
08949
08950
08951
08952
08953
08954
08955
08956
08957
08958
08959
08960
08961
08962
08963
08964
08965
08966
08967
08968
08969
08970
08971
08972
08973
08974
08975
08976
08977
08978
08979
08980
08981
08982
08983
08984
08985
08986
08987
08988
08989
08990
08991
08992
08993
08994
08995
08996
08997
08998
08999 static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
09000 {
09001 int res;
09002 int lastnum = 0;
09003
09004 res = ast_play_and_wait(chan, "vm-youhave");
09005
09006 if (!res && vms->newmessages) {
09007 lastnum = vms->newmessages;
09008
09009 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, ast_channel_language(chan), message_gender))) {
09010 res = ast_say_counted_adjective(chan, lastnum, "vm-new", message_gender);
09011 }
09012
09013 if (!res && vms->oldmessages) {
09014 res = ast_play_and_wait(chan, "vm-and");
09015 }
09016 }
09017
09018 if (!res && vms->oldmessages) {
09019 lastnum = vms->oldmessages;
09020
09021 if (!(res = ast_say_number(chan, lastnum, AST_DIGIT_ANY, ast_channel_language(chan), message_gender))) {
09022 res = ast_say_counted_adjective(chan, lastnum, "vm-old", message_gender);
09023 }
09024 }
09025
09026 if (!res) {
09027 if (lastnum == 0) {
09028 res = ast_play_and_wait(chan, "vm-no");
09029 }
09030 if (!res) {
09031 res = ast_say_counted_noun(chan, lastnum, "vm-message");
09032 }
09033 }
09034
09035 return res;
09036 }
09037
09038
09039 static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
09040 {
09041 int res = 0;
09042
09043
09044 if (!res) {
09045 if ((vms->newmessages) || (vms->oldmessages)) {
09046 res = ast_play_and_wait(chan, "vm-youhave");
09047 }
09048
09049
09050
09051
09052
09053 if (vms->newmessages) {
09054 if (!res) {
09055 if (vms->newmessages == 1) {
09056 res = ast_play_and_wait(chan, "vm-INBOX1");
09057 } else {
09058 if (vms->newmessages == 2) {
09059 res = ast_play_and_wait(chan, "vm-shtei");
09060 } else {
09061 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
09062 }
09063 res = ast_play_and_wait(chan, "vm-INBOX");
09064 }
09065 }
09066 if (vms->oldmessages && !res) {
09067 res = ast_play_and_wait(chan, "vm-and");
09068 if (vms->oldmessages == 1) {
09069 res = ast_play_and_wait(chan, "vm-Old1");
09070 } else {
09071 if (vms->oldmessages == 2) {
09072 res = ast_play_and_wait(chan, "vm-shtei");
09073 } else {
09074 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
09075 }
09076 res = ast_play_and_wait(chan, "vm-Old");
09077 }
09078 }
09079 }
09080 if (!res && vms->oldmessages && !vms->newmessages) {
09081 if (!res) {
09082 if (vms->oldmessages == 1) {
09083 res = ast_play_and_wait(chan, "vm-Old1");
09084 } else {
09085 if (vms->oldmessages == 2) {
09086 res = ast_play_and_wait(chan, "vm-shtei");
09087 } else {
09088 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
09089 }
09090 res = ast_play_and_wait(chan, "vm-Old");
09091 }
09092 }
09093 }
09094 if (!res) {
09095 if (!vms->oldmessages && !vms->newmessages) {
09096 if (!res) {
09097 res = ast_play_and_wait(chan, "vm-nomessages");
09098 }
09099 }
09100 }
09101 }
09102 return res;
09103 }
09104
09105
09106 static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
09107 {
09108 int res;
09109
09110
09111 res = ast_play_and_wait(chan, "vm-youhave");
09112 if (!res) {
09113 if (vms->urgentmessages) {
09114 res = say_and_wait(chan, vms->urgentmessages, ast_channel_language(chan));
09115 if (!res)
09116 res = ast_play_and_wait(chan, "vm-Urgent");
09117 if ((vms->oldmessages || vms->newmessages) && !res) {
09118 res = ast_play_and_wait(chan, "vm-and");
09119 } else if (!res) {
09120 if ((vms->urgentmessages == 1))
09121 res = ast_play_and_wait(chan, "vm-message");
09122 else
09123 res = ast_play_and_wait(chan, "vm-messages");
09124 }
09125 }
09126 if (vms->newmessages) {
09127 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
09128 if (!res)
09129 res = ast_play_and_wait(chan, "vm-INBOX");
09130 if (vms->oldmessages && !res)
09131 res = ast_play_and_wait(chan, "vm-and");
09132 else if (!res) {
09133 if ((vms->newmessages == 1))
09134 res = ast_play_and_wait(chan, "vm-message");
09135 else
09136 res = ast_play_and_wait(chan, "vm-messages");
09137 }
09138
09139 }
09140 if (!res && vms->oldmessages) {
09141 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
09142 if (!res)
09143 res = ast_play_and_wait(chan, "vm-Old");
09144 if (!res) {
09145 if (vms->oldmessages == 1)
09146 res = ast_play_and_wait(chan, "vm-message");
09147 else
09148 res = ast_play_and_wait(chan, "vm-messages");
09149 }
09150 }
09151 if (!res) {
09152 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
09153 res = ast_play_and_wait(chan, "vm-no");
09154 if (!res)
09155 res = ast_play_and_wait(chan, "vm-messages");
09156 }
09157 }
09158 }
09159 return res;
09160 }
09161
09162
09163 static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
09164 {
09165
09166 int res;
09167 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
09168 res = ast_play_and_wait(chan, "vm-no") ||
09169 ast_play_and_wait(chan, "vm-message");
09170 else
09171 res = ast_play_and_wait(chan, "vm-youhave");
09172 if (!res && vms->newmessages) {
09173 res = (vms->newmessages == 1) ?
09174 ast_play_and_wait(chan, "digits/un") ||
09175 ast_play_and_wait(chan, "vm-nuovo") ||
09176 ast_play_and_wait(chan, "vm-message") :
09177
09178 say_and_wait(chan, vms->newmessages, ast_channel_language(chan)) ||
09179 ast_play_and_wait(chan, "vm-nuovi") ||
09180 ast_play_and_wait(chan, "vm-messages");
09181 if (!res && vms->oldmessages)
09182 res = ast_play_and_wait(chan, "vm-and");
09183 }
09184 if (!res && vms->oldmessages) {
09185 res = (vms->oldmessages == 1) ?
09186 ast_play_and_wait(chan, "digits/un") ||
09187 ast_play_and_wait(chan, "vm-vecchio") ||
09188 ast_play_and_wait(chan, "vm-message") :
09189
09190 say_and_wait(chan, vms->oldmessages, ast_channel_language(chan)) ||
09191 ast_play_and_wait(chan, "vm-vecchi") ||
09192 ast_play_and_wait(chan, "vm-messages");
09193 }
09194 return res;
09195 }
09196
09197
09198 static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
09199 {
09200
09201 int res;
09202 div_t num;
09203
09204 if (!vms->oldmessages && !vms->newmessages) {
09205 res = ast_play_and_wait(chan, "vm-no");
09206 res = res ? res : ast_play_and_wait(chan, "vm-messages");
09207 return res;
09208 } else {
09209 res = ast_play_and_wait(chan, "vm-youhave");
09210 }
09211
09212 if (vms->newmessages) {
09213 num = div(vms->newmessages, 10);
09214 if (vms->newmessages == 1) {
09215 res = ast_play_and_wait(chan, "digits/1-a");
09216 res = res ? res : ast_play_and_wait(chan, "vm-new-a");
09217 res = res ? res : ast_play_and_wait(chan, "vm-message");
09218 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
09219 if (num.rem == 2) {
09220 if (!num.quot) {
09221 res = ast_play_and_wait(chan, "digits/2-ie");
09222 } else {
09223 res = say_and_wait(chan, vms->newmessages - 2 , ast_channel_language(chan));
09224 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
09225 }
09226 } else {
09227 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
09228 }
09229 res = res ? res : ast_play_and_wait(chan, "vm-new-e");
09230 res = res ? res : ast_play_and_wait(chan, "vm-messages");
09231 } else {
09232 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
09233 res = res ? res : ast_play_and_wait(chan, "vm-new-ych");
09234 res = res ? res : ast_play_and_wait(chan, "vm-messages");
09235 }
09236 if (!res && vms->oldmessages)
09237 res = ast_play_and_wait(chan, "vm-and");
09238 }
09239 if (!res && vms->oldmessages) {
09240 num = div(vms->oldmessages, 10);
09241 if (vms->oldmessages == 1) {
09242 res = ast_play_and_wait(chan, "digits/1-a");
09243 res = res ? res : ast_play_and_wait(chan, "vm-old-a");
09244 res = res ? res : ast_play_and_wait(chan, "vm-message");
09245 } else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
09246 if (num.rem == 2) {
09247 if (!num.quot) {
09248 res = ast_play_and_wait(chan, "digits/2-ie");
09249 } else {
09250 res = say_and_wait(chan, vms->oldmessages - 2 , ast_channel_language(chan));
09251 res = res ? res : ast_play_and_wait(chan, "digits/2-ie");
09252 }
09253 } else {
09254 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
09255 }
09256 res = res ? res : ast_play_and_wait(chan, "vm-old-e");
09257 res = res ? res : ast_play_and_wait(chan, "vm-messages");
09258 } else {
09259 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
09260 res = res ? res : ast_play_and_wait(chan, "vm-old-ych");
09261 res = res ? res : ast_play_and_wait(chan, "vm-messages");
09262 }
09263 }
09264
09265 return res;
09266 }
09267
09268
09269 static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
09270 {
09271
09272 int res;
09273
09274 res = ast_play_and_wait(chan, "vm-youhave");
09275 if (res)
09276 return res;
09277
09278 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
09279 res = ast_play_and_wait(chan, "vm-no");
09280 res = res ? res : ast_play_and_wait(chan, "vm-messages");
09281 return res;
09282 }
09283
09284 if (vms->newmessages) {
09285 if ((vms->newmessages == 1)) {
09286 res = ast_play_and_wait(chan, "digits/ett");
09287 res = res ? res : ast_play_and_wait(chan, "vm-nytt");
09288 res = res ? res : ast_play_and_wait(chan, "vm-message");
09289 } else {
09290 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
09291 res = res ? res : ast_play_and_wait(chan, "vm-nya");
09292 res = res ? res : ast_play_and_wait(chan, "vm-messages");
09293 }
09294 if (!res && vms->oldmessages)
09295 res = ast_play_and_wait(chan, "vm-and");
09296 }
09297 if (!res && vms->oldmessages) {
09298 if (vms->oldmessages == 1) {
09299 res = ast_play_and_wait(chan, "digits/ett");
09300 res = res ? res : ast_play_and_wait(chan, "vm-gammalt");
09301 res = res ? res : ast_play_and_wait(chan, "vm-message");
09302 } else {
09303 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
09304 res = res ? res : ast_play_and_wait(chan, "vm-gamla");
09305 res = res ? res : ast_play_and_wait(chan, "vm-messages");
09306 }
09307 }
09308
09309 return res;
09310 }
09311
09312
09313 static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
09314 {
09315
09316 int res;
09317
09318 res = ast_play_and_wait(chan, "vm-youhave");
09319 if (res)
09320 return res;
09321
09322 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
09323 res = ast_play_and_wait(chan, "vm-no");
09324 res = res ? res : ast_play_and_wait(chan, "vm-messages");
09325 return res;
09326 }
09327
09328 if (vms->newmessages) {
09329 if ((vms->newmessages == 1)) {
09330 res = ast_play_and_wait(chan, "digits/1");
09331 res = res ? res : ast_play_and_wait(chan, "vm-ny");
09332 res = res ? res : ast_play_and_wait(chan, "vm-message");
09333 } else {
09334 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
09335 res = res ? res : ast_play_and_wait(chan, "vm-nye");
09336 res = res ? res : ast_play_and_wait(chan, "vm-messages");
09337 }
09338 if (!res && vms->oldmessages)
09339 res = ast_play_and_wait(chan, "vm-and");
09340 }
09341 if (!res && vms->oldmessages) {
09342 if (vms->oldmessages == 1) {
09343 res = ast_play_and_wait(chan, "digits/1");
09344 res = res ? res : ast_play_and_wait(chan, "vm-gamel");
09345 res = res ? res : ast_play_and_wait(chan, "vm-message");
09346 } else {
09347 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
09348 res = res ? res : ast_play_and_wait(chan, "vm-gamle");
09349 res = res ? res : ast_play_and_wait(chan, "vm-messages");
09350 }
09351 }
09352
09353 return res;
09354 }
09355
09356
09357 static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
09358 {
09359
09360 int res;
09361 res = ast_play_and_wait(chan, "vm-youhave");
09362 if (!res) {
09363 if (vms->newmessages) {
09364 if ((vms->newmessages == 1))
09365 res = ast_play_and_wait(chan, "digits/1F");
09366 else
09367 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
09368 if (!res)
09369 res = ast_play_and_wait(chan, "vm-INBOX");
09370 if (vms->oldmessages && !res)
09371 res = ast_play_and_wait(chan, "vm-and");
09372 else if (!res) {
09373 if ((vms->newmessages == 1))
09374 res = ast_play_and_wait(chan, "vm-message");
09375 else
09376 res = ast_play_and_wait(chan, "vm-messages");
09377 }
09378
09379 }
09380 if (!res && vms->oldmessages) {
09381 if (vms->oldmessages == 1)
09382 res = ast_play_and_wait(chan, "digits/1F");
09383 else
09384 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
09385 if (!res)
09386 res = ast_play_and_wait(chan, "vm-Old");
09387 if (!res) {
09388 if (vms->oldmessages == 1)
09389 res = ast_play_and_wait(chan, "vm-message");
09390 else
09391 res = ast_play_and_wait(chan, "vm-messages");
09392 }
09393 }
09394 if (!res) {
09395 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
09396 res = ast_play_and_wait(chan, "vm-no");
09397 if (!res)
09398 res = ast_play_and_wait(chan, "vm-messages");
09399 }
09400 }
09401 }
09402 return res;
09403 }
09404
09405
09406 static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
09407 {
09408
09409 int res;
09410 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
09411 res = ast_play_and_wait(chan, "vm-youhaveno");
09412 if (!res)
09413 res = ast_play_and_wait(chan, "vm-messages");
09414 } else {
09415 res = ast_play_and_wait(chan, "vm-youhave");
09416 }
09417 if (!res) {
09418 if (vms->newmessages) {
09419 if (!res) {
09420 if ((vms->newmessages == 1)) {
09421 res = ast_play_and_wait(chan, "digits/1M");
09422 if (!res)
09423 res = ast_play_and_wait(chan, "vm-message");
09424 if (!res)
09425 res = ast_play_and_wait(chan, "vm-INBOXs");
09426 } else {
09427 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
09428 if (!res)
09429 res = ast_play_and_wait(chan, "vm-messages");
09430 if (!res)
09431 res = ast_play_and_wait(chan, "vm-INBOX");
09432 }
09433 }
09434 if (vms->oldmessages && !res)
09435 res = ast_play_and_wait(chan, "vm-and");
09436 }
09437 if (vms->oldmessages) {
09438 if (!res) {
09439 if (vms->oldmessages == 1) {
09440 res = ast_play_and_wait(chan, "digits/1M");
09441 if (!res)
09442 res = ast_play_and_wait(chan, "vm-message");
09443 if (!res)
09444 res = ast_play_and_wait(chan, "vm-Olds");
09445 } else {
09446 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
09447 if (!res)
09448 res = ast_play_and_wait(chan, "vm-messages");
09449 if (!res)
09450 res = ast_play_and_wait(chan, "vm-Old");
09451 }
09452 }
09453 }
09454 }
09455 return res;
09456 }
09457
09458
09459 static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms) {
09460
09461 int res;
09462 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
09463 res = ast_play_and_wait(chan, "vm-nomessages");
09464 return res;
09465 } else {
09466 res = ast_play_and_wait(chan, "vm-youhave");
09467 }
09468 if (vms->newmessages) {
09469 if (!res)
09470 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
09471 if ((vms->newmessages == 1)) {
09472 if (!res)
09473 res = ast_play_and_wait(chan, "vm-message");
09474 if (!res)
09475 res = ast_play_and_wait(chan, "vm-INBOXs");
09476 } else {
09477 if (!res)
09478 res = ast_play_and_wait(chan, "vm-messages");
09479 if (!res)
09480 res = ast_play_and_wait(chan, "vm-INBOX");
09481 }
09482 if (vms->oldmessages && !res)
09483 res = ast_play_and_wait(chan, "vm-and");
09484 }
09485 if (vms->oldmessages) {
09486 if (!res)
09487 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
09488 if (vms->oldmessages == 1) {
09489 if (!res)
09490 res = ast_play_and_wait(chan, "vm-message");
09491 if (!res)
09492 res = ast_play_and_wait(chan, "vm-Olds");
09493 } else {
09494 if (!res)
09495 res = ast_play_and_wait(chan, "vm-messages");
09496 if (!res)
09497 res = ast_play_and_wait(chan, "vm-Old");
09498 }
09499 }
09500 return res;
09501 }
09502
09503
09504 static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
09505 {
09506
09507 int res;
09508 res = ast_play_and_wait(chan, "vm-youhave");
09509 if (!res) {
09510 if (vms->newmessages) {
09511 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
09512 if (!res)
09513 res = ast_play_and_wait(chan, "vm-INBOX");
09514 if (vms->oldmessages && !res)
09515 res = ast_play_and_wait(chan, "vm-and");
09516 else if (!res) {
09517 if ((vms->newmessages == 1))
09518 res = ast_play_and_wait(chan, "vm-message");
09519 else
09520 res = ast_play_and_wait(chan, "vm-messages");
09521 }
09522
09523 }
09524 if (!res && vms->oldmessages) {
09525 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
09526 if (!res)
09527 res = ast_play_and_wait(chan, "vm-Old");
09528 if (!res) {
09529 if (vms->oldmessages == 1)
09530 res = ast_play_and_wait(chan, "vm-message");
09531 else
09532 res = ast_play_and_wait(chan, "vm-messages");
09533 }
09534 }
09535 if (!res) {
09536 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
09537 res = ast_play_and_wait(chan, "vm-no");
09538 if (!res)
09539 res = ast_play_and_wait(chan, "vm-messages");
09540 }
09541 }
09542 }
09543 return res;
09544 }
09545
09546
09547 static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
09548 {
09549
09550 int res;
09551 res = ast_play_and_wait(chan, "vm-youhave");
09552 if (!res) {
09553 if (vms->newmessages) {
09554 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
09555 if (!res) {
09556 if (vms->newmessages == 1)
09557 res = ast_play_and_wait(chan, "vm-INBOXs");
09558 else
09559 res = ast_play_and_wait(chan, "vm-INBOX");
09560 }
09561 if (vms->oldmessages && !res)
09562 res = ast_play_and_wait(chan, "vm-and");
09563 else if (!res) {
09564 if ((vms->newmessages == 1))
09565 res = ast_play_and_wait(chan, "vm-message");
09566 else
09567 res = ast_play_and_wait(chan, "vm-messages");
09568 }
09569
09570 }
09571 if (!res && vms->oldmessages) {
09572 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
09573 if (!res) {
09574 if (vms->oldmessages == 1)
09575 res = ast_play_and_wait(chan, "vm-Olds");
09576 else
09577 res = ast_play_and_wait(chan, "vm-Old");
09578 }
09579 if (!res) {
09580 if (vms->oldmessages == 1)
09581 res = ast_play_and_wait(chan, "vm-message");
09582 else
09583 res = ast_play_and_wait(chan, "vm-messages");
09584 }
09585 }
09586 if (!res) {
09587 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
09588 res = ast_play_and_wait(chan, "vm-no");
09589 if (!res)
09590 res = ast_play_and_wait(chan, "vm-messages");
09591 }
09592 }
09593 }
09594 return res;
09595 }
09596
09597
09598 static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
09599 {
09600
09601 int res;
09602 res = ast_play_and_wait(chan, "vm-youhave");
09603 if (!res) {
09604 if (vms->newmessages) {
09605 res = ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
09606 if (!res) {
09607 if ((vms->newmessages == 1)) {
09608 res = ast_play_and_wait(chan, "vm-message");
09609 if (!res)
09610 res = ast_play_and_wait(chan, "vm-INBOXs");
09611 } else {
09612 res = ast_play_and_wait(chan, "vm-messages");
09613 if (!res)
09614 res = ast_play_and_wait(chan, "vm-INBOX");
09615 }
09616 }
09617 if (vms->oldmessages && !res)
09618 res = ast_play_and_wait(chan, "vm-and");
09619 }
09620 if (!res && vms->oldmessages) {
09621 res = ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), "f");
09622 if (!res) {
09623 if (vms->oldmessages == 1) {
09624 res = ast_play_and_wait(chan, "vm-message");
09625 if (!res)
09626 res = ast_play_and_wait(chan, "vm-Olds");
09627 } else {
09628 res = ast_play_and_wait(chan, "vm-messages");
09629 if (!res)
09630 res = ast_play_and_wait(chan, "vm-Old");
09631 }
09632 }
09633 }
09634 if (!res) {
09635 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
09636 res = ast_play_and_wait(chan, "vm-no");
09637 if (!res)
09638 res = ast_play_and_wait(chan, "vm-messages");
09639 }
09640 }
09641 }
09642 return res;
09643 }
09644
09645
09646
09647
09648
09649
09650
09651
09652
09653
09654
09655
09656
09657
09658
09659
09660
09661 static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
09662 {
09663 int res;
09664 res = ast_play_and_wait(chan, "vm-youhave");
09665 if (!res) {
09666 if (vms->newmessages) {
09667 if (vms->newmessages == 1) {
09668 res = ast_play_and_wait(chan, "digits/jednu");
09669 } else {
09670 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
09671 }
09672 if (!res) {
09673 if ((vms->newmessages == 1))
09674 res = ast_play_and_wait(chan, "vm-novou");
09675 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
09676 res = ast_play_and_wait(chan, "vm-nove");
09677 if (vms->newmessages > 4)
09678 res = ast_play_and_wait(chan, "vm-novych");
09679 }
09680 if (vms->oldmessages && !res)
09681 res = ast_play_and_wait(chan, "vm-and");
09682 else if (!res) {
09683 if ((vms->newmessages == 1))
09684 res = ast_play_and_wait(chan, "vm-zpravu");
09685 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
09686 res = ast_play_and_wait(chan, "vm-zpravy");
09687 if (vms->newmessages > 4)
09688 res = ast_play_and_wait(chan, "vm-zprav");
09689 }
09690 }
09691 if (!res && vms->oldmessages) {
09692 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
09693 if (!res) {
09694 if ((vms->oldmessages == 1))
09695 res = ast_play_and_wait(chan, "vm-starou");
09696 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
09697 res = ast_play_and_wait(chan, "vm-stare");
09698 if (vms->oldmessages > 4)
09699 res = ast_play_and_wait(chan, "vm-starych");
09700 }
09701 if (!res) {
09702 if ((vms->oldmessages == 1))
09703 res = ast_play_and_wait(chan, "vm-zpravu");
09704 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
09705 res = ast_play_and_wait(chan, "vm-zpravy");
09706 if (vms->oldmessages > 4)
09707 res = ast_play_and_wait(chan, "vm-zprav");
09708 }
09709 }
09710 if (!res) {
09711 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
09712 res = ast_play_and_wait(chan, "vm-no");
09713 if (!res)
09714 res = ast_play_and_wait(chan, "vm-zpravy");
09715 }
09716 }
09717 }
09718 return res;
09719 }
09720
09721
09722 static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
09723 {
09724 int res;
09725
09726 res = ast_play_and_wait(chan, "vm-you");
09727
09728 if (!res && vms->newmessages) {
09729 res = ast_play_and_wait(chan, "vm-have");
09730 if (!res)
09731 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
09732 if (!res)
09733 res = ast_play_and_wait(chan, "vm-tong");
09734 if (!res)
09735 res = ast_play_and_wait(chan, "vm-INBOX");
09736 if (vms->oldmessages && !res)
09737 res = ast_play_and_wait(chan, "vm-and");
09738 else if (!res)
09739 res = ast_play_and_wait(chan, "vm-messages");
09740 }
09741 if (!res && vms->oldmessages) {
09742 res = ast_play_and_wait(chan, "vm-have");
09743 if (!res)
09744 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
09745 if (!res)
09746 res = ast_play_and_wait(chan, "vm-tong");
09747 if (!res)
09748 res = ast_play_and_wait(chan, "vm-Old");
09749 if (!res)
09750 res = ast_play_and_wait(chan, "vm-messages");
09751 }
09752 if (!res && !vms->oldmessages && !vms->newmessages) {
09753 res = ast_play_and_wait(chan, "vm-haveno");
09754 if (!res)
09755 res = ast_play_and_wait(chan, "vm-messages");
09756 }
09757 return res;
09758 }
09759
09760
09761 static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
09762 {
09763 int res;
09764
09765
09766 res = ast_play_and_wait(chan, "vm-youhave");
09767 if (!res) {
09768 if (vms->newmessages) {
09769 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
09770 if (!res)
09771 res = ast_play_and_wait(chan, "vm-INBOX");
09772 if (vms->oldmessages && !res)
09773 res = ast_play_and_wait(chan, "vm-and");
09774 }
09775 if (!res && vms->oldmessages) {
09776 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
09777 if (!res)
09778 res = ast_play_and_wait(chan, "vm-Old");
09779 }
09780 if (!res) {
09781 if (!vms->oldmessages && !vms->newmessages) {
09782 res = ast_play_and_wait(chan, "vm-no");
09783 if (!res)
09784 res = ast_play_and_wait(chan, "vm-message");
09785 }
09786 }
09787 }
09788 return res;
09789 }
09790
09791 static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
09792 {
09793 char prefile[256];
09794
09795
09796 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
09797 if (ast_test_flag(vmu, VM_TEMPGREETWARN)) {
09798 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
09799 if (ast_fileexists(prefile, NULL, NULL) > 0) {
09800 ast_play_and_wait(chan, "vm-tempgreetactive");
09801 }
09802 DISPOSE(prefile, -1);
09803 }
09804
09805
09806 if (0) {
09807 return 0;
09808 } else if (!strncasecmp(ast_channel_language(chan), "cs", 2)) {
09809 return vm_intro_cs(chan, vms);
09810 } else if (!strncasecmp(ast_channel_language(chan), "cz", 2)) {
09811 static int deprecation_warning = 0;
09812 if (deprecation_warning++ % 10 == 0) {
09813 ast_log(LOG_WARNING, "cz is not a standard language code. Please switch to using cs instead.\n");
09814 }
09815 return vm_intro_cs(chan, vms);
09816 } else if (!strncasecmp(ast_channel_language(chan), "de", 2)) {
09817 return vm_intro_de(chan, vms);
09818 } else if (!strncasecmp(ast_channel_language(chan), "es", 2)) {
09819 return vm_intro_es(chan, vms);
09820 } else if (!strncasecmp(ast_channel_language(chan), "fr", 2)) {
09821 return vm_intro_fr(chan, vms);
09822 } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) {
09823 return vm_intro_gr(chan, vms);
09824 } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) {
09825 return vm_intro_he(chan, vms);
09826 } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) {
09827 return vm_intro_it(chan, vms);
09828 } else if (!strncasecmp(ast_channel_language(chan), "nl", 2)) {
09829 return vm_intro_nl(chan, vms);
09830 } else if (!strncasecmp(ast_channel_language(chan), "no", 2)) {
09831 return vm_intro_no(chan, vms);
09832 } else if (!strncasecmp(ast_channel_language(chan), "pl", 2)) {
09833 return vm_intro_pl(chan, vms);
09834 } else if (!strncasecmp(ast_channel_language(chan), "pt_BR", 5)) {
09835 return vm_intro_pt_BR(chan, vms);
09836 } else if (!strncasecmp(ast_channel_language(chan), "pt", 2)) {
09837 return vm_intro_pt(chan, vms);
09838 } else if (!strncasecmp(ast_channel_language(chan), "ru", 2)) {
09839 return vm_intro_multilang(chan, vms, "n");
09840 } else if (!strncasecmp(ast_channel_language(chan), "se", 2)) {
09841 return vm_intro_se(chan, vms);
09842 } else if (!strncasecmp(ast_channel_language(chan), "ua", 2)) {
09843 return vm_intro_multilang(chan, vms, "n");
09844 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {
09845 return vm_intro_vi(chan, vms);
09846 } else if (!strncasecmp(ast_channel_language(chan), "zh", 2)) {
09847 return vm_intro_zh(chan, vms);
09848 } else {
09849 return vm_intro_en(chan, vms);
09850 }
09851 }
09852
09853 static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09854 {
09855 int res = 0;
09856
09857 while (!res) {
09858 if (vms->starting) {
09859 if (vms->lastmsg > -1) {
09860 if (skipadvanced)
09861 res = ast_play_and_wait(chan, "vm-onefor-full");
09862 else
09863 res = ast_play_and_wait(chan, "vm-onefor");
09864 if (!res)
09865 res = vm_play_folder_name(chan, vms->vmbox);
09866 }
09867 if (!res) {
09868 if (skipadvanced)
09869 res = ast_play_and_wait(chan, "vm-opts-full");
09870 else
09871 res = ast_play_and_wait(chan, "vm-opts");
09872 }
09873 } else {
09874
09875 if (skipadvanced) {
09876 res = ast_play_and_wait(chan, "vm-onefor-full");
09877 if (!res)
09878 res = vm_play_folder_name(chan, vms->vmbox);
09879 res = ast_play_and_wait(chan, "vm-opts-full");
09880 }
09881
09882
09883
09884
09885
09886
09887 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
09888 res = ast_play_and_wait(chan, "vm-prev");
09889 }
09890 if (!res && !skipadvanced)
09891 res = ast_play_and_wait(chan, "vm-advopts");
09892 if (!res)
09893 res = ast_play_and_wait(chan, "vm-repeat");
09894
09895
09896
09897
09898
09899
09900 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
09901 (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms->lastmsg > 0) )) {
09902 res = ast_play_and_wait(chan, "vm-next");
09903 }
09904 if (!res) {
09905 int curmsg_deleted;
09906 #ifdef IMAP_STORAGE
09907 ast_mutex_lock(&vms->lock);
09908 #endif
09909 curmsg_deleted = vms->deleted[vms->curmsg];
09910 #ifdef IMAP_STORAGE
09911 ast_mutex_unlock(&vms->lock);
09912 #endif
09913 if (!curmsg_deleted) {
09914 res = ast_play_and_wait(chan, "vm-delete");
09915 } else {
09916 res = ast_play_and_wait(chan, "vm-undelete");
09917 }
09918 if (!res) {
09919 res = ast_play_and_wait(chan, "vm-toforward");
09920 }
09921 if (!res) {
09922 res = ast_play_and_wait(chan, "vm-savemessage");
09923 }
09924 }
09925 }
09926 if (!res) {
09927 res = ast_play_and_wait(chan, "vm-helpexit");
09928 }
09929 if (!res)
09930 res = ast_waitfordigit(chan, 6000);
09931 if (!res) {
09932 vms->repeats++;
09933 if (vms->repeats > 2) {
09934 res = 't';
09935 }
09936 }
09937 }
09938 return res;
09939 }
09940
09941 static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09942 {
09943 int res = 0;
09944
09945 while (!res) {
09946 if (vms->lastmsg > -1) {
09947 res = ast_play_and_wait(chan, "vm-listen");
09948 if (!res)
09949 res = vm_play_folder_name(chan, vms->vmbox);
09950 if (!res)
09951 res = ast_play_and_wait(chan, "press");
09952 if (!res)
09953 res = ast_play_and_wait(chan, "digits/1");
09954 }
09955 if (!res)
09956 res = ast_play_and_wait(chan, "vm-opts");
09957 if (!res) {
09958 vms->starting = 0;
09959 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09960 }
09961 }
09962 return res;
09963 }
09964
09965 static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
09966 {
09967 if (vms->starting && !strncasecmp(ast_channel_language(chan), "zh", 2)) {
09968 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent);
09969 } else {
09970 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent);
09971 }
09972 }
09973
09974
09975 static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
09976 {
09977 int cmd = 0;
09978 int duration = 0;
09979 int tries = 0;
09980 char newpassword[80] = "";
09981 char newpassword2[80] = "";
09982 char prefile[PATH_MAX] = "";
09983 unsigned char buf[256];
09984 int bytes = 0;
09985
09986 ast_test_suite_event_notify("NEWUSER", "Message: entering new user state");
09987 if (ast_adsi_available(chan)) {
09988 bytes += adsi_logo(buf + bytes);
09989 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
09990 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
09991 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
09992 bytes += ast_adsi_voice_mode(buf + bytes, 0);
09993 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
09994 }
09995
09996
09997 if (ast_test_flag(vmu, VM_FORCENAME)) {
09998 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
09999 if (ast_fileexists(prefile, NULL, NULL) < 1) {
10000 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL);
10001 if (cmd < 0 || cmd == 't' || cmd == '#')
10002 return cmd;
10003 }
10004 }
10005
10006
10007 if (ast_test_flag(vmu, VM_FORCEGREET)) {
10008 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
10009 if (ast_fileexists(prefile, NULL, NULL) < 1) {
10010 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL);
10011 if (cmd < 0 || cmd == 't' || cmd == '#')
10012 return cmd;
10013 }
10014
10015 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
10016 if (ast_fileexists(prefile, NULL, NULL) < 1) {
10017 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL);
10018 if (cmd < 0 || cmd == 't' || cmd == '#')
10019 return cmd;
10020 }
10021 }
10022
10023
10024
10025
10026
10027 for (;;) {
10028 newpassword[1] = '\0';
10029 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
10030 if (cmd == '#')
10031 newpassword[0] = '\0';
10032 if (cmd < 0 || cmd == 't' || cmd == '#')
10033 return cmd;
10034 cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#");
10035 if (cmd < 0 || cmd == 't' || cmd == '#')
10036 return cmd;
10037 cmd = check_password(vmu, newpassword);
10038 if (cmd != 0) {
10039 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
10040 cmd = ast_play_and_wait(chan, vm_invalid_password);
10041 } else {
10042 newpassword2[1] = '\0';
10043 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
10044 if (cmd == '#')
10045 newpassword2[0] = '\0';
10046 if (cmd < 0 || cmd == 't' || cmd == '#')
10047 return cmd;
10048 cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#");
10049 if (cmd < 0 || cmd == 't' || cmd == '#')
10050 return cmd;
10051 if (!strcmp(newpassword, newpassword2))
10052 break;
10053 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
10054 cmd = ast_play_and_wait(chan, vm_mismatch);
10055 }
10056 if (++tries == 3)
10057 return -1;
10058 if (cmd != 0) {
10059 cmd = ast_play_and_wait(chan, vm_pls_try_again);
10060 }
10061 }
10062 if (pwdchange & PWDCHANGE_INTERNAL)
10063 vm_change_password(vmu, newpassword);
10064 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
10065 vm_change_password_shell(vmu, newpassword);
10066
10067 ast_debug(1, "User %s set password to %s of length %d\n", vms->username, newpassword, (int) strlen(newpassword));
10068 cmd = ast_play_and_wait(chan, vm_passchanged);
10069
10070 return cmd;
10071 }
10072
10073 static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
10074 {
10075 int cmd = 0;
10076 int retries = 0;
10077 int duration = 0;
10078 char newpassword[80] = "";
10079 char newpassword2[80] = "";
10080 char prefile[PATH_MAX] = "";
10081 unsigned char buf[256];
10082 int bytes = 0;
10083
10084 ast_test_suite_event_notify("VMOPTIONS", "Message: entering mailbox options");
10085 if (ast_adsi_available(chan)) {
10086 bytes += adsi_logo(buf + bytes);
10087 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
10088 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
10089 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
10090 bytes += ast_adsi_voice_mode(buf + bytes, 0);
10091 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
10092 }
10093 while ((cmd >= 0) && (cmd != 't')) {
10094 if (cmd)
10095 retries = 0;
10096 switch (cmd) {
10097 case '1':
10098 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
10099 cmd = play_record_review(chan, "vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL);
10100 break;
10101 case '2':
10102 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
10103 cmd = play_record_review(chan, "vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL);
10104 break;
10105 case '3':
10106 snprintf(prefile, sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
10107 cmd = play_record_review(chan, "vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL);
10108 break;
10109 case '4':
10110 cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
10111 break;
10112 case '5':
10113 if (vmu->password[0] == '-') {
10114 cmd = ast_play_and_wait(chan, "vm-no");
10115 break;
10116 }
10117 newpassword[1] = '\0';
10118 newpassword[0] = cmd = ast_play_and_wait(chan, vm_newpassword);
10119 if (cmd == '#')
10120 newpassword[0] = '\0';
10121 else {
10122 if (cmd < 0)
10123 break;
10124 if ((cmd = ast_readstring(chan, newpassword + strlen(newpassword), sizeof(newpassword) - 1, 2000, 10000, "#")) < 0) {
10125 break;
10126 }
10127 }
10128 cmd = check_password(vmu, newpassword);
10129 if (cmd != 0) {
10130 ast_log(AST_LOG_NOTICE, "Invalid password for user %s (%s)\n", vms->username, newpassword);
10131 cmd = ast_play_and_wait(chan, vm_invalid_password);
10132 if (!cmd) {
10133 cmd = ast_play_and_wait(chan, vm_pls_try_again);
10134 }
10135 break;
10136 }
10137 newpassword2[1] = '\0';
10138 newpassword2[0] = cmd = ast_play_and_wait(chan, vm_reenterpassword);
10139 if (cmd == '#')
10140 newpassword2[0] = '\0';
10141 else {
10142 if (cmd < 0)
10143 break;
10144
10145 if ((cmd = ast_readstring(chan, newpassword2 + strlen(newpassword2), sizeof(newpassword2) - 1, 2000, 10000, "#")) < 0) {
10146 break;
10147 }
10148 }
10149 if (strcmp(newpassword, newpassword2)) {
10150 ast_log(AST_LOG_NOTICE, "Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
10151 cmd = ast_play_and_wait(chan, vm_mismatch);
10152 if (!cmd) {
10153 cmd = ast_play_and_wait(chan, vm_pls_try_again);
10154 }
10155 break;
10156 }
10157
10158 if (pwdchange & PWDCHANGE_INTERNAL) {
10159 vm_change_password(vmu, newpassword);
10160 }
10161 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
10162 vm_change_password_shell(vmu, newpassword);
10163 }
10164
10165 ast_debug(1, "User %s set password to %s of length %d\n",
10166 vms->username, newpassword, (int) strlen(newpassword));
10167 cmd = ast_play_and_wait(chan, vm_passchanged);
10168 break;
10169 case '*':
10170 cmd = 't';
10171 break;
10172 default:
10173 cmd = 0;
10174 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
10175 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
10176 if (ast_fileexists(prefile, NULL, NULL)) {
10177 cmd = ast_play_and_wait(chan, "vm-tmpexists");
10178 }
10179 DISPOSE(prefile, -1);
10180 if (!cmd) {
10181 cmd = ast_play_and_wait(chan, "vm-options");
10182 }
10183 if (!cmd) {
10184 cmd = ast_waitfordigit(chan, 6000);
10185 }
10186 if (!cmd) {
10187 retries++;
10188 }
10189 if (retries > 3) {
10190 cmd = 't';
10191 }
10192 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10193 }
10194 }
10195 if (cmd == 't')
10196 cmd = 0;
10197 return cmd;
10198 }
10199
10200
10201
10202
10203
10204
10205
10206
10207
10208
10209
10210
10211
10212
10213
10214
10215
10216 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
10217 {
10218 int cmd = 0;
10219 int retries = 0;
10220 int duration = 0;
10221 char prefile[PATH_MAX] = "";
10222 unsigned char buf[256];
10223 int bytes = 0;
10224
10225 if (ast_adsi_available(chan)) {
10226 bytes += adsi_logo(buf + bytes);
10227 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
10228 bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
10229 bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
10230 bytes += ast_adsi_voice_mode(buf + bytes, 0);
10231 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
10232 }
10233
10234 ast_test_suite_event_notify("TEMPGREETING", "Message: entering temp greeting options");
10235 snprintf(prefile, sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
10236 while ((cmd >= 0) && (cmd != 't')) {
10237 if (cmd)
10238 retries = 0;
10239 RETRIEVE(prefile, -1, vmu->mailbox, vmu->context);
10240 if (ast_fileexists(prefile, NULL, NULL) <= 0) {
10241 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL);
10242 if (cmd == -1) {
10243 break;
10244 }
10245 cmd = 't';
10246 } else {
10247 switch (cmd) {
10248 case '1':
10249 cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL);
10250 break;
10251 case '2':
10252 DELETE(prefile, -1, prefile, vmu);
10253 ast_play_and_wait(chan, "vm-tempremoved");
10254 cmd = 't';
10255 break;
10256 case '*':
10257 cmd = 't';
10258 break;
10259 default:
10260 cmd = ast_play_and_wait(chan,
10261 ast_fileexists(prefile, NULL, NULL) > 0 ?
10262 "vm-tempgreeting2" : "vm-tempgreeting");
10263 if (!cmd) {
10264 cmd = ast_waitfordigit(chan, 6000);
10265 }
10266 if (!cmd) {
10267 retries++;
10268 }
10269 if (retries > 3) {
10270 cmd = 't';
10271 }
10272 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
10273 }
10274 }
10275 DISPOSE(prefile, -1);
10276 }
10277 if (cmd == 't')
10278 cmd = 0;
10279 return cmd;
10280 }
10281
10282
10283
10284
10285
10286
10287
10288
10289
10290 static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
10291 {
10292 int cmd = 0;
10293
10294 if (vms->lastmsg > -1) {
10295 cmd = play_message(chan, vmu, vms);
10296 } else {
10297 cmd = ast_play_and_wait(chan, "vm-youhaveno");
10298 if (!strcasecmp(vms->vmbox, "vm-INBOX") ||!strcasecmp(vms->vmbox, "vm-Old")){
10299 if (!cmd) {
10300 snprintf(vms->fn, sizeof(vms->fn), "vm-%ss", vms->curbox);
10301 cmd = ast_play_and_wait(chan, vms->fn);
10302 }
10303 if (!cmd)
10304 cmd = ast_play_and_wait(chan, "vm-messages");
10305 } else {
10306 if (!cmd)
10307 cmd = ast_play_and_wait(chan, "vm-messages");
10308 if (!cmd) {
10309 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
10310 cmd = ast_play_and_wait(chan, vms->fn);
10311 }
10312 }
10313 }
10314 return cmd;
10315 }
10316
10317
10318 static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
10319 {
10320 int cmd = 0;
10321
10322 if (vms->lastmsg > -1) {
10323 cmd = play_message(chan, vmu, vms);
10324 } else {
10325 if (!strcasecmp(vms->fn, "INBOX")) {
10326 cmd = ast_play_and_wait(chan, "vm-nonewmessages");
10327 } else {
10328 cmd = ast_play_and_wait(chan, "vm-nomessages");
10329 }
10330 }
10331 return cmd;
10332 }
10333
10334
10335
10336
10337
10338
10339
10340
10341
10342 static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
10343 {
10344 int cmd = 0;
10345
10346 if (vms->lastmsg > -1) {
10347 cmd = play_message(chan, vmu, vms);
10348 } else {
10349 cmd = ast_play_and_wait(chan, "vm-youhave");
10350 if (!cmd)
10351 cmd = ast_play_and_wait(chan, "vm-no");
10352 if (!cmd) {
10353 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
10354 cmd = ast_play_and_wait(chan, vms->fn);
10355 }
10356 if (!cmd)
10357 cmd = ast_play_and_wait(chan, "vm-messages");
10358 }
10359 return cmd;
10360 }
10361
10362
10363
10364
10365
10366
10367
10368
10369
10370 static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
10371 {
10372 int cmd;
10373
10374 if (vms->lastmsg > -1) {
10375 cmd = play_message(chan, vmu, vms);
10376 } else {
10377 cmd = ast_play_and_wait(chan, "vm-no");
10378 if (!cmd)
10379 cmd = ast_play_and_wait(chan, "vm-message");
10380 if (!cmd) {
10381 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
10382 cmd = ast_play_and_wait(chan, vms->fn);
10383 }
10384 }
10385 return cmd;
10386 }
10387
10388
10389
10390
10391
10392
10393
10394
10395
10396 static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
10397 {
10398 int cmd;
10399
10400 if (vms->lastmsg > -1) {
10401 cmd = play_message(chan, vmu, vms);
10402 } else {
10403 cmd = ast_play_and_wait(chan, "vm-youhaveno");
10404 if (!cmd)
10405 cmd = ast_play_and_wait(chan, "vm-messages");
10406 if (!cmd) {
10407 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
10408 cmd = ast_play_and_wait(chan, vms->fn);
10409 }
10410 }
10411 return cmd;
10412 }
10413
10414
10415
10416
10417
10418
10419
10420
10421
10422 static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
10423 {
10424 int cmd;
10425
10426 if (vms->lastmsg > -1) {
10427 cmd = play_message(chan, vmu, vms);
10428 } else {
10429 cmd = ast_play_and_wait(chan, "vm-no");
10430 if (!cmd) {
10431 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
10432 cmd = ast_play_and_wait(chan, vms->fn);
10433 }
10434 if (!cmd)
10435 cmd = ast_play_and_wait(chan, "vm-messages");
10436 }
10437 return cmd;
10438 }
10439
10440
10441
10442
10443
10444
10445
10446
10447
10448 static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
10449 {
10450 int cmd;
10451
10452 if (vms->lastmsg > -1) {
10453 cmd = play_message(chan, vmu, vms);
10454 } else {
10455 cmd = ast_play_and_wait(chan, "vm-you");
10456 if (!cmd)
10457 cmd = ast_play_and_wait(chan, "vm-haveno");
10458 if (!cmd)
10459 cmd = ast_play_and_wait(chan, "vm-messages");
10460 if (!cmd) {
10461 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
10462 cmd = ast_play_and_wait(chan, vms->fn);
10463 }
10464 }
10465 return cmd;
10466 }
10467
10468
10469
10470
10471
10472
10473
10474
10475
10476 static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
10477 {
10478 int cmd = 0;
10479
10480 if (vms->lastmsg > -1) {
10481 cmd = play_message(chan, vmu, vms);
10482 } else {
10483 cmd = ast_play_and_wait(chan, "vm-no");
10484 if (!cmd) {
10485 snprintf(vms->fn, sizeof(vms->fn), "vm-%s", vms->curbox);
10486 cmd = ast_play_and_wait(chan, vms->fn);
10487 }
10488 }
10489 return cmd;
10490 }
10491
10492
10493
10494
10495
10496
10497
10498
10499
10500
10501
10502
10503 static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
10504 {
10505 if (!strncasecmp(ast_channel_language(chan), "es", 2)) {
10506 return vm_browse_messages_es(chan, vms, vmu);
10507 } else if (!strncasecmp(ast_channel_language(chan), "gr", 2)) {
10508 return vm_browse_messages_gr(chan, vms, vmu);
10509 } else if (!strncasecmp(ast_channel_language(chan), "he", 2)) {
10510 return vm_browse_messages_he(chan, vms, vmu);
10511 } else if (!strncasecmp(ast_channel_language(chan), "it", 2)) {
10512 return vm_browse_messages_it(chan, vms, vmu);
10513 } else if (!strncasecmp(ast_channel_language(chan), "pt", 2)) {
10514 return vm_browse_messages_pt(chan, vms, vmu);
10515 } else if (!strncasecmp(ast_channel_language(chan), "vi", 2)) {
10516 return vm_browse_messages_vi(chan, vms, vmu);
10517 } else if (!strncasecmp(ast_channel_language(chan), "zh", 2)) {
10518 return vm_browse_messages_zh(chan, vms, vmu);
10519 } else {
10520 return vm_browse_messages_en(chan, vms, vmu);
10521 }
10522 }
10523
10524 static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size,
10525 struct ast_vm_user *res_vmu, const char *context, const char *prefix,
10526 int skipuser, int max_logins, int silent)
10527 {
10528 int useadsi = 0, valid = 0, logretries = 0;
10529 char password[AST_MAX_EXTENSION]="", *passptr;
10530 struct ast_vm_user vmus, *vmu = NULL;
10531
10532
10533 adsi_begin(chan, &useadsi);
10534 if (!skipuser && useadsi)
10535 adsi_login(chan);
10536 ast_test_suite_event_notify("PLAYBACK", "Message: vm-login");
10537 if (!silent && !skipuser && ast_streamfile(chan, "vm-login", ast_channel_language(chan))) {
10538 ast_log(AST_LOG_WARNING, "Couldn't stream login file\n");
10539 return -1;
10540 }
10541
10542
10543
10544 while (!valid && (logretries < max_logins)) {
10545
10546 if (!skipuser && ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000, "#") < 0) {
10547 ast_log(AST_LOG_WARNING, "Couldn't read username\n");
10548 return -1;
10549 }
10550 if (ast_strlen_zero(mailbox)) {
10551 if (ast_channel_caller(chan)->id.number.valid && ast_channel_caller(chan)->id.number.str) {
10552 ast_copy_string(mailbox, ast_channel_caller(chan)->id.number.str, mailbox_size);
10553 } else {
10554 ast_verb(3, "Username not entered\n");
10555 return -1;
10556 }
10557 } else if (mailbox[0] == '*') {
10558
10559 ast_verb(4, "Mailbox begins with '*', attempting jump to extension 'a'\n");
10560 if (ast_exists_extension(chan, ast_channel_context(chan), "a", 1,
10561 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
10562 return -1;
10563 }
10564 ast_verb(4, "Jump to extension 'a' failed; setting mailbox to NULL\n");
10565 mailbox[0] = '\0';
10566 }
10567
10568 if (useadsi)
10569 adsi_password(chan);
10570
10571 if (!ast_strlen_zero(prefix)) {
10572 char fullusername[80] = "";
10573 ast_copy_string(fullusername, prefix, sizeof(fullusername));
10574 strncat(fullusername, mailbox, sizeof(fullusername) - 1 - strlen(fullusername));
10575 ast_copy_string(mailbox, fullusername, mailbox_size);
10576 }
10577
10578 ast_debug(1, "Before find user for mailbox %s\n", mailbox);
10579 vmu = find_user(&vmus, context, mailbox);
10580 if (vmu && (vmu->password[0] == '\0' || (vmu->password[0] == '-' && vmu->password[1] == '\0'))) {
10581
10582 password[0] = '\0';
10583 } else {
10584 ast_test_suite_event_notify("PLAYBACK", "Message: %s", vm_password);
10585 if (ast_streamfile(chan, vm_password, ast_channel_language(chan))) {
10586 ast_log(AST_LOG_WARNING, "Unable to stream password file\n");
10587 return -1;
10588 }
10589 if (ast_readstring(chan, password, sizeof(password) - 1, 2000, 10000, "#") < 0) {
10590 ast_log(AST_LOG_WARNING, "Unable to read password\n");
10591 return -1;
10592 } else if (password[0] == '*') {
10593
10594 ast_verb(4, "Password begins with '*', attempting jump to extension 'a'\n");
10595 if (ast_exists_extension(chan, ast_channel_context(chan), "a", 1,
10596 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
10597 mailbox[0] = '*';
10598 return -1;
10599 }
10600 ast_verb(4, "Jump to extension 'a' failed; setting mailbox and user to NULL\n");
10601 mailbox[0] = '\0';
10602
10603 vmu = NULL;
10604 }
10605 }
10606
10607 if (vmu) {
10608 passptr = vmu->password;
10609 if (passptr[0] == '-') passptr++;
10610 }
10611 if (vmu && !strcmp(passptr, password))
10612 valid++;
10613 else {
10614 ast_verb(3, "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
10615 if (!ast_strlen_zero(prefix))
10616 mailbox[0] = '\0';
10617 }
10618 logretries++;
10619 if (!valid) {
10620 if (skipuser || logretries >= max_logins) {
10621 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect");
10622 if (ast_streamfile(chan, "vm-incorrect", ast_channel_language(chan))) {
10623 ast_log(AST_LOG_WARNING, "Unable to stream incorrect message\n");
10624 return -1;
10625 }
10626 } else {
10627 ast_test_suite_event_notify("PLAYBACK", "Message: vm-incorrect-mailbox");
10628 if (useadsi)
10629 adsi_login(chan);
10630 if (ast_streamfile(chan, "vm-incorrect-mailbox", ast_channel_language(chan))) {
10631 ast_log(AST_LOG_WARNING, "Unable to stream incorrect mailbox message\n");
10632 return -1;
10633 }
10634 }
10635 if (ast_waitstream(chan, ""))
10636 return -1;
10637 }
10638 }
10639 if (!valid && (logretries >= max_logins)) {
10640 ast_stopstream(chan);
10641 ast_play_and_wait(chan, "vm-goodbye");
10642 return -1;
10643 }
10644 if (vmu && !skipuser) {
10645 memcpy(res_vmu, vmu, sizeof(struct ast_vm_user));
10646 }
10647 return 0;
10648 }
10649
10650 static int play_message_by_id_helper(struct ast_channel *chan,
10651 struct ast_vm_user *vmu,
10652 struct vm_state *vms,
10653 const char *msg_id)
10654 {
10655 if (message_range_and_existence_check(vms, &msg_id, 1, &vms->curmsg, vmu)) {
10656 return -1;
10657 }
10658
10659
10660 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
10661 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
10662
10663 #ifdef IMAP_STORAGE
10664
10665
10666
10667 if (!ast_strlen_zero(vms->introfn) && ast_fileexists(vms->introfn, NULL, NULL) > 0) {
10668 wait_file(chan, vms, vms->introfn);
10669 }
10670 #endif
10671 if ((wait_file(chan, vms, vms->fn)) < 0) {
10672 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms->fn);
10673 } else {
10674 #ifdef IMAP_STORAGE
10675 ast_mutex_lock(&vms->lock);
10676 #endif
10677 vms->heard[vms->curmsg] = 1;
10678 #ifdef IMAP_STORAGE
10679 ast_mutex_unlock(&vms->lock);
10680 #endif
10681 }
10682
10683 return 0;
10684 }
10685
10686
10687
10688
10689
10690
10691
10692 static int play_message_by_id(struct ast_channel *chan, const char *mailbox, const char *context, const char *msg_id)
10693 {
10694 struct vm_state vms;
10695 struct ast_vm_user *vmu = NULL, vmus;
10696 int res = 0;
10697 int open = 0;
10698 int played = 0;
10699 int i;
10700
10701 memset(&vmus, 0, sizeof(vmus));
10702 memset(&vms, 0, sizeof(vms));
10703
10704 if (!(vmu = find_user(&vmus, context, mailbox))) {
10705 goto play_msg_cleanup;
10706 }
10707
10708
10709 for (i = 0; i < ARRAY_LEN(mailbox_folders) && !played; i++) {
10710 ast_copy_string(vms.username, mailbox, sizeof(vms.username));
10711 vms.lastmsg = -1;
10712
10713
10714 if ((res = open_mailbox(&vms, vmu, i)) < 0) {
10715 ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
10716 res = -1;
10717 goto play_msg_cleanup;
10718 }
10719 open = 1;
10720
10721
10722 if ((vms.lastmsg != -1) && !(play_message_by_id_helper(chan, vmu, &vms, msg_id))) {
10723 played = 1;
10724 }
10725
10726
10727 if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
10728 res = -1;
10729 goto play_msg_cleanup;
10730 }
10731 open = 0;
10732 }
10733
10734 play_msg_cleanup:
10735 if (!played) {
10736 res = -1;
10737 }
10738
10739 if (vmu && open) {
10740 close_mailbox(&vms, vmu);
10741 }
10742
10743 #ifdef IMAP_STORAGE
10744 if (vmu) {
10745 vmstate_delete(&vms);
10746 }
10747 #endif
10748
10749 return res;
10750 }
10751
10752 static int vm_playmsgexec(struct ast_channel *chan, const char *data)
10753 {
10754 char *parse;
10755 char *mailbox = NULL;
10756 char *context = NULL;
10757 int res;
10758
10759 AST_DECLARE_APP_ARGS(args,
10760 AST_APP_ARG(mailbox);
10761 AST_APP_ARG(msg_id);
10762 );
10763
10764 if (ast_channel_state(chan) != AST_STATE_UP) {
10765 ast_debug(1, "Before ast_answer\n");
10766 ast_answer(chan);
10767 }
10768
10769 if (ast_strlen_zero(data)) {
10770 return -1;
10771 }
10772
10773 parse = ast_strdupa(data);
10774 AST_STANDARD_APP_ARGS(args, parse);
10775
10776 if (ast_strlen_zero(args.mailbox) || ast_strlen_zero(args.msg_id)) {
10777 return -1;
10778 }
10779
10780 if ((context = strchr(args.mailbox, '@'))) {
10781 *context++ = '\0';
10782 }
10783 mailbox = args.mailbox;
10784
10785 res = play_message_by_id(chan, mailbox, context, args.msg_id);
10786 pbx_builtin_setvar_helper(chan, "VOICEMAIL_PLAYBACKSTATUS", res ? "FAILED" : "SUCCESS");
10787
10788 return 0;
10789 }
10790
10791 static int vm_execmain(struct ast_channel *chan, const char *data)
10792 {
10793
10794
10795
10796 int res = -1;
10797 int cmd = 0;
10798 int valid = 0;
10799 char prefixstr[80] ="";
10800 char ext_context[256]="";
10801 int box;
10802 int useadsi = 0;
10803 int skipuser = 0;
10804 struct vm_state vms;
10805 struct ast_vm_user *vmu = NULL, vmus;
10806 char *context = NULL;
10807 int silentexit = 0;
10808 struct ast_flags flags = { 0 };
10809 signed char record_gain = 0;
10810 int play_auto = 0;
10811 int play_folder = 0;
10812 int in_urgent = 0;
10813 #ifdef IMAP_STORAGE
10814 int deleted = 0;
10815 #endif
10816
10817
10818 memset(&vms, 0, sizeof(vms));
10819
10820 vms.lastmsg = -1;
10821
10822 memset(&vmus, 0, sizeof(vmus));
10823
10824 ast_test_suite_event_notify("START", "Message: vm_execmain started");
10825 if (ast_channel_state(chan) != AST_STATE_UP) {
10826 ast_debug(1, "Before ast_answer\n");
10827 ast_answer(chan);
10828 }
10829
10830 if (!ast_strlen_zero(data)) {
10831 char *opts[OPT_ARG_ARRAY_SIZE];
10832 char *parse;
10833 AST_DECLARE_APP_ARGS(args,
10834 AST_APP_ARG(argv0);
10835 AST_APP_ARG(argv1);
10836 );
10837
10838 parse = ast_strdupa(data);
10839
10840 AST_STANDARD_APP_ARGS(args, parse);
10841
10842 if (args.argc == 2) {
10843 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
10844 return -1;
10845 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
10846 int gain;
10847 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
10848 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
10849 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10850 return -1;
10851 } else {
10852 record_gain = (signed char) gain;
10853 }
10854 } else {
10855 ast_log(AST_LOG_WARNING, "Invalid Gain level set with option g\n");
10856 }
10857 }
10858 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
10859 play_auto = 1;
10860 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
10861
10862 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
10863 if (sscanf(opts[OPT_ARG_PLAYFOLDER], "%30d", &play_folder) != 1) {
10864 play_folder = -1;
10865 }
10866 } else {
10867 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
10868 }
10869 } else {
10870 ast_log(AST_LOG_WARNING, "Invalid folder set with option a\n");
10871 }
10872 if (play_folder > 9 || play_folder < 0) {
10873 ast_log(AST_LOG_WARNING,
10874 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
10875 opts[OPT_ARG_PLAYFOLDER]);
10876 play_folder = 0;
10877 }
10878 }
10879 } else {
10880
10881 while (*(args.argv0)) {
10882 if (*(args.argv0) == 's')
10883 ast_set_flag(&flags, OPT_SILENT);
10884 else if (*(args.argv0) == 'p')
10885 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
10886 else
10887 break;
10888 (args.argv0)++;
10889 }
10890
10891 }
10892
10893 valid = ast_test_flag(&flags, OPT_SILENT);
10894
10895 if ((context = strchr(args.argv0, '@')))
10896 *context++ = '\0';
10897
10898 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
10899 ast_copy_string(prefixstr, args.argv0, sizeof(prefixstr));
10900 else
10901 ast_copy_string(vms.username, args.argv0, sizeof(vms.username));
10902
10903 if (!ast_strlen_zero(vms.username) && (vmu = find_user(&vmus, context ,vms.username)))
10904 skipuser++;
10905 else
10906 valid = 0;
10907 }
10908
10909 if (!valid)
10910 res = vm_authenticate(chan, vms.username, sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
10911
10912 ast_debug(1, "After vm_authenticate\n");
10913
10914 if (vms.username[0] == '*') {
10915 ast_debug(1, "user pressed * in context '%s'\n", ast_channel_context(chan));
10916
10917
10918 if (!ast_goto_if_exists(chan, ast_channel_context(chan), "a", 1)) {
10919 ast_test_suite_event_notify("REDIRECT", "Message: redirecting user to 'a' extension");
10920 res = 0;
10921 goto out;
10922 }
10923 }
10924
10925 if (!res) {
10926 valid = 1;
10927 if (!skipuser)
10928 vmu = &vmus;
10929 } else {
10930 res = 0;
10931 }
10932
10933
10934 adsi_begin(chan, &useadsi);
10935
10936 ast_test_suite_assert(valid);
10937 if (!valid) {
10938 goto out;
10939 }
10940 ast_test_suite_event_notify("AUTHENTICATED", "Message: vm_user authenticated");
10941
10942 #ifdef IMAP_STORAGE
10943 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10944 pthread_setspecific(ts_vmstate.key, &vms);
10945
10946 vms.interactive = 1;
10947 vms.updated = 1;
10948 if (vmu)
10949 ast_copy_string(vms.context, vmu->context, sizeof(vms.context));
10950 vmstate_insert(&vms);
10951 init_vm_state(&vms);
10952 #endif
10953
10954
10955 if (!ast_strlen_zero(vmu->language))
10956 ast_channel_language_set(chan, vmu->language);
10957
10958
10959 ast_debug(1, "Before open_mailbox\n");
10960 res = open_mailbox(&vms, vmu, OLD_FOLDER);
10961 if (res < 0)
10962 goto out;
10963 vms.oldmessages = vms.lastmsg + 1;
10964 ast_debug(1, "Number of old messages: %d\n", vms.oldmessages);
10965
10966 res = open_mailbox(&vms, vmu, NEW_FOLDER);
10967 if (res < 0)
10968 goto out;
10969 vms.newmessages = vms.lastmsg + 1;
10970 ast_debug(1, "Number of new messages: %d\n", vms.newmessages);
10971
10972 in_urgent = 1;
10973 res = open_mailbox(&vms, vmu, 11);
10974 if (res < 0)
10975 goto out;
10976 vms.urgentmessages = vms.lastmsg + 1;
10977 ast_debug(1, "Number of urgent messages: %d\n", vms.urgentmessages);
10978
10979
10980 if (play_auto) {
10981 ast_test_suite_event_notify("AUTOPLAY", "Message: auto-playing messages");
10982 if (vms.urgentmessages) {
10983 in_urgent = 1;
10984 res = open_mailbox(&vms, vmu, 11);
10985 } else {
10986 in_urgent = 0;
10987 res = open_mailbox(&vms, vmu, play_folder);
10988 }
10989 if (res < 0)
10990 goto out;
10991
10992
10993 if (vms.lastmsg == -1) {
10994 in_urgent = 0;
10995 cmd = vm_browse_messages(chan, &vms, vmu);
10996 res = 0;
10997 goto out;
10998 }
10999 } else {
11000 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
11001
11002 res = open_mailbox(&vms, vmu, OLD_FOLDER);
11003 in_urgent = 0;
11004 play_folder = 1;
11005 if (res < 0)
11006 goto out;
11007 } else if (!vms.urgentmessages && vms.newmessages) {
11008
11009 in_urgent = 0;
11010 res = open_mailbox(&vms, vmu, NEW_FOLDER);
11011 if (res < 0)
11012 goto out;
11013 }
11014 }
11015
11016 if (useadsi)
11017 adsi_status(chan, &vms);
11018 res = 0;
11019
11020
11021 if (!strcasecmp(vmu->mailbox, vmu->password) &&
11022 (ast_test_flag(vmu, VM_FORCENAME | VM_FORCEGREET))) {
11023 if (ast_play_and_wait(chan, "vm-newuser") == -1)
11024 ast_log(AST_LOG_WARNING, "Couldn't stream new user file\n");
11025 cmd = vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
11026 if ((cmd == 't') || (cmd == '#')) {
11027
11028 ast_test_suite_event_notify("TIMEOUT", "Message: response from user timed out");
11029 res = 0;
11030 goto out;
11031 } else if (cmd < 0) {
11032
11033 ast_test_suite_event_notify("HANGUP", "Message: hangup detected");
11034 res = -1;
11035 goto out;
11036 }
11037 }
11038 #ifdef IMAP_STORAGE
11039 ast_debug(3, "Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
11040 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
11041 ast_debug(1, "*** QUOTA EXCEEDED!!\n");
11042 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
11043 }
11044 ast_debug(3, "Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
11045 if ((vms.newmessages + vms.oldmessages) >= vmu->maxmsg) {
11046 ast_log(AST_LOG_WARNING, "No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->maxmsg);
11047 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
11048 }
11049 #endif
11050
11051 ast_test_suite_event_notify("INTRO", "Message: playing intro menu");
11052 if (play_auto) {
11053 cmd = '1';
11054 } else {
11055 cmd = vm_intro(chan, vmu, &vms);
11056 }
11057 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
11058
11059 vms.repeats = 0;
11060 vms.starting = 1;
11061 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
11062
11063 switch (cmd) {
11064 case '1':
11065 vms.curmsg = 0;
11066
11067 case '5':
11068 ast_test_suite_event_notify("BROWSE", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
11069 cmd = vm_browse_messages(chan, &vms, vmu);
11070 break;
11071 case '2':
11072 ast_test_suite_event_notify("CHANGEFOLDER", "Message: browsing to a different folder");
11073 if (useadsi)
11074 adsi_folders(chan, 0, "Change to folder...");
11075
11076 cmd = get_folder2(chan, "vm-changeto", 0);
11077 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
11078 if (cmd == '#') {
11079 cmd = 0;
11080 } else if (cmd > 0) {
11081 cmd = cmd - '0';
11082 res = close_mailbox(&vms, vmu);
11083 if (res == ERROR_LOCK_PATH)
11084 goto out;
11085
11086 if (cmd != 11) in_urgent = 0;
11087 res = open_mailbox(&vms, vmu, cmd);
11088 if (res < 0)
11089 goto out;
11090 play_folder = cmd;
11091 cmd = 0;
11092 }
11093 if (useadsi)
11094 adsi_status2(chan, &vms);
11095
11096 if (!cmd) {
11097 cmd = vm_play_folder_name(chan, vms.vmbox);
11098 }
11099
11100 vms.starting = 1;
11101 vms.curmsg = 0;
11102 break;
11103 case '3':
11104 ast_test_suite_event_notify("ADVOPTIONS", "Message: entering advanced options menu");
11105 cmd = 0;
11106 vms.repeats = 0;
11107 while ((cmd > -1) && (cmd != 't') && (cmd != '#')) {
11108 switch (cmd) {
11109 case '1':
11110 if (vms.lastmsg > -1 && !vms.starting) {
11111 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 1, record_gain);
11112 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
11113 res = cmd;
11114 goto out;
11115 }
11116 } else {
11117 cmd = ast_play_and_wait(chan, "vm-sorry");
11118 }
11119 cmd = 't';
11120 break;
11121 case '2':
11122 if (!vms.starting)
11123 ast_verb(3, "Callback Requested\n");
11124 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
11125 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 2, record_gain);
11126 if (cmd == 9) {
11127 silentexit = 1;
11128 goto out;
11129 } else if (cmd == ERROR_LOCK_PATH) {
11130 res = cmd;
11131 goto out;
11132 }
11133 } else {
11134 cmd = ast_play_and_wait(chan, "vm-sorry");
11135 }
11136 cmd = 't';
11137 break;
11138 case '3':
11139 if (vms.lastmsg > -1 && !vms.starting) {
11140 cmd = advanced_options(chan, vmu, &vms, vms.curmsg, 3, record_gain);
11141 if (cmd == ERROR_LOCK_PATH) {
11142 res = cmd;
11143 goto out;
11144 }
11145 } else {
11146 cmd = ast_play_and_wait(chan, "vm-sorry");
11147 }
11148 cmd = 't';
11149 break;
11150 case '4':
11151 if (!ast_strlen_zero(vmu->dialout)) {
11152 cmd = dialout(chan, vmu, NULL, vmu->dialout);
11153 if (cmd == 9) {
11154 silentexit = 1;
11155 goto out;
11156 }
11157 } else {
11158 cmd = ast_play_and_wait(chan, "vm-sorry");
11159 }
11160 cmd = 't';
11161 break;
11162
11163 case '5':
11164 if (ast_test_flag(vmu, VM_SVMAIL)) {
11165 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
11166 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
11167 res = cmd;
11168 goto out;
11169 }
11170 } else {
11171 cmd = ast_play_and_wait(chan, "vm-sorry");
11172 }
11173 cmd = 't';
11174 break;
11175
11176 case '*':
11177 cmd = 't';
11178 break;
11179
11180 default:
11181 cmd = 0;
11182 if (!vms.starting) {
11183 cmd = ast_play_and_wait(chan, "vm-toreply");
11184 }
11185 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
11186 cmd = ast_play_and_wait(chan, "vm-tocallback");
11187 }
11188 if (!cmd && !vms.starting) {
11189 cmd = ast_play_and_wait(chan, "vm-tohearenv");
11190 }
11191 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
11192 cmd = ast_play_and_wait(chan, "vm-tomakecall");
11193 }
11194 if (ast_test_flag(vmu, VM_SVMAIL) && !cmd) {
11195 cmd = ast_play_and_wait(chan, "vm-leavemsg");
11196 }
11197 if (!cmd) {
11198 cmd = ast_play_and_wait(chan, "vm-starmain");
11199 }
11200 if (!cmd) {
11201 cmd = ast_waitfordigit(chan, 6000);
11202 }
11203 if (!cmd) {
11204 vms.repeats++;
11205 }
11206 if (vms.repeats > 3) {
11207 cmd = 't';
11208 }
11209 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
11210 }
11211 }
11212 if (cmd == 't') {
11213 cmd = 0;
11214 vms.repeats = 0;
11215 }
11216 break;
11217 case '4':
11218 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg - 1, vms.curmsg - 1);
11219 if (vms.curmsg > 0) {
11220 vms.curmsg--;
11221 cmd = play_message(chan, vmu, &vms);
11222 } else {
11223
11224
11225
11226
11227 if (in_urgent == 0 && vms.urgentmessages > 0) {
11228
11229 in_urgent = 1;
11230 res = close_mailbox(&vms, vmu);
11231 if (res == ERROR_LOCK_PATH)
11232 goto out;
11233 res = open_mailbox(&vms, vmu, 11);
11234 if (res < 0)
11235 goto out;
11236 ast_debug(1, "No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
11237 vms.curmsg = vms.lastmsg;
11238 if (vms.lastmsg < 0) {
11239 cmd = ast_play_and_wait(chan, "vm-nomore");
11240 }
11241 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
11242 vms.curmsg = vms.lastmsg;
11243 cmd = play_message(chan, vmu, &vms);
11244 } else {
11245 cmd = ast_play_and_wait(chan, "vm-nomore");
11246 }
11247 }
11248 break;
11249 case '6':
11250 ast_test_suite_event_notify("PREVMSG", "Message: browsing message %d\r\nVoicemail: %d", vms.curmsg + 1, vms.curmsg + 1);
11251 if (vms.curmsg < vms.lastmsg) {
11252 vms.curmsg++;
11253 cmd = play_message(chan, vmu, &vms);
11254 } else {
11255 if (in_urgent && vms.newmessages > 0) {
11256
11257
11258
11259
11260 in_urgent = 0;
11261 res = close_mailbox(&vms, vmu);
11262 if (res == ERROR_LOCK_PATH)
11263 goto out;
11264 res = open_mailbox(&vms, vmu, NEW_FOLDER);
11265 if (res < 0)
11266 goto out;
11267 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
11268 vms.curmsg = -1;
11269 if (vms.lastmsg < 0) {
11270 cmd = ast_play_and_wait(chan, "vm-nomore");
11271 }
11272 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
11273 vms.curmsg = 0;
11274 cmd = play_message(chan, vmu, &vms);
11275 } else {
11276 cmd = ast_play_and_wait(chan, "vm-nomore");
11277 }
11278 }
11279 break;
11280 case '7':
11281 if (vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
11282 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
11283 if (useadsi)
11284 adsi_delete(chan, &vms);
11285 if (vms.deleted[vms.curmsg]) {
11286 if (play_folder == 0) {
11287 if (in_urgent) {
11288 vms.urgentmessages--;
11289 } else {
11290 vms.newmessages--;
11291 }
11292 }
11293 else if (play_folder == 1)
11294 vms.oldmessages--;
11295 cmd = ast_play_and_wait(chan, "vm-deleted");
11296 } else {
11297 if (play_folder == 0) {
11298 if (in_urgent) {
11299 vms.urgentmessages++;
11300 } else {
11301 vms.newmessages++;
11302 }
11303 }
11304 else if (play_folder == 1)
11305 vms.oldmessages++;
11306 cmd = ast_play_and_wait(chan, "vm-undeleted");
11307 }
11308 if (ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
11309 if (vms.curmsg < vms.lastmsg) {
11310 vms.curmsg++;
11311 cmd = play_message(chan, vmu, &vms);
11312 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
11313 vms.curmsg = 0;
11314 cmd = play_message(chan, vmu, &vms);
11315 } else {
11316
11317
11318
11319
11320 if (in_urgent == 1) {
11321
11322 in_urgent = 0;
11323 res = close_mailbox(&vms, vmu);
11324 if (res == ERROR_LOCK_PATH)
11325 goto out;
11326 res = open_mailbox(&vms, vmu, NEW_FOLDER);
11327 if (res < 0)
11328 goto out;
11329 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
11330 vms.curmsg = -1;
11331 if (vms.lastmsg < 0) {
11332 cmd = ast_play_and_wait(chan, "vm-nomore");
11333 }
11334 } else {
11335 cmd = ast_play_and_wait(chan, "vm-nomore");
11336 }
11337 }
11338 }
11339 } else
11340 cmd = 0;
11341 #ifdef IMAP_STORAGE
11342 deleted = 1;
11343 #endif
11344 break;
11345
11346 case '8':
11347 if (vms.lastmsg > -1) {
11348 cmd = forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
11349 if (cmd == ERROR_LOCK_PATH) {
11350 res = cmd;
11351 goto out;
11352 }
11353 } else {
11354
11355
11356
11357
11358 if (in_urgent == 1 && vms.newmessages > 0) {
11359
11360 in_urgent = 0;
11361 res = close_mailbox(&vms, vmu);
11362 if (res == ERROR_LOCK_PATH)
11363 goto out;
11364 res = open_mailbox(&vms, vmu, NEW_FOLDER);
11365 if (res < 0)
11366 goto out;
11367 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
11368 vms.curmsg = -1;
11369 if (vms.lastmsg < 0) {
11370 cmd = ast_play_and_wait(chan, "vm-nomore");
11371 }
11372 } else {
11373 cmd = ast_play_and_wait(chan, "vm-nomore");
11374 }
11375 }
11376 break;
11377 case '9':
11378 ast_test_suite_event_notify("SAVEMSG", "Message: saving message %d\r\nVoicemail: %d", vms.curmsg, vms.curmsg);
11379 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
11380
11381 cmd = 0;
11382 break;
11383 }
11384 if (useadsi)
11385 adsi_folders(chan, 1, "Save to folder...");
11386 cmd = get_folder2(chan, "vm-savefolder", 1);
11387 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
11388 box = 0;
11389 if (cmd == '#') {
11390 cmd = 0;
11391 break;
11392 } else if (cmd > 0) {
11393 box = cmd = cmd - '0';
11394 cmd = save_to_folder(vmu, &vms, vms.curmsg, cmd, NULL, 0);
11395 if (cmd == ERROR_LOCK_PATH) {
11396 res = cmd;
11397 goto out;
11398 #ifndef IMAP_STORAGE
11399 } else if (!cmd) {
11400 vms.deleted[vms.curmsg] = 1;
11401 #endif
11402 } else {
11403 vms.deleted[vms.curmsg] = 0;
11404 vms.heard[vms.curmsg] = 0;
11405 }
11406 }
11407 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
11408 if (useadsi)
11409 adsi_message(chan, &vms);
11410 snprintf(vms.fn, sizeof(vms.fn), "vm-%s", mbox(vmu, box));
11411 if (!cmd) {
11412 cmd = ast_play_and_wait(chan, "vm-message");
11413 if (!cmd)
11414 cmd = say_and_wait(chan, vms.curmsg + 1, ast_channel_language(chan));
11415 if (!cmd)
11416 cmd = ast_play_and_wait(chan, "vm-savedto");
11417 if (!cmd)
11418 cmd = vm_play_folder_name(chan, vms.fn);
11419 } else {
11420 cmd = ast_play_and_wait(chan, "vm-mailboxfull");
11421 }
11422 if (ast_test_flag((&globalflags), VM_SKIPAFTERCMD)) {
11423 if (vms.curmsg < vms.lastmsg) {
11424 vms.curmsg++;
11425 cmd = play_message(chan, vmu, &vms);
11426 } else if (ast_test_flag(vmu, VM_MESSAGEWRAP) && vms.lastmsg > 0) {
11427 vms.curmsg = 0;
11428 cmd = play_message(chan, vmu, &vms);
11429 } else {
11430
11431
11432
11433
11434 if (in_urgent == 1 && vms.newmessages > 0) {
11435
11436 in_urgent = 0;
11437 res = close_mailbox(&vms, vmu);
11438 if (res == ERROR_LOCK_PATH)
11439 goto out;
11440 res = open_mailbox(&vms, vmu, NEW_FOLDER);
11441 if (res < 0)
11442 goto out;
11443 ast_debug(1, "No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
11444 vms.curmsg = -1;
11445 if (vms.lastmsg < 0) {
11446 cmd = ast_play_and_wait(chan, "vm-nomore");
11447 }
11448 } else {
11449 cmd = ast_play_and_wait(chan, "vm-nomore");
11450 }
11451 }
11452 }
11453 break;
11454 case '*':
11455 if (!vms.starting) {
11456 cmd = ast_play_and_wait(chan, "vm-onefor");
11457 if (!strncasecmp(ast_channel_language(chan), "he", 2)) {
11458 cmd = ast_play_and_wait(chan, "vm-for");
11459 }
11460 if (!cmd)
11461 cmd = vm_play_folder_name(chan, vms.vmbox);
11462 if (!cmd)
11463 cmd = ast_play_and_wait(chan, "vm-opts");
11464 if (!cmd)
11465 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent);
11466 } else
11467 cmd = 0;
11468 break;
11469 case '0':
11470 cmd = vm_options(chan, vmu, &vms, vmfmts, record_gain);
11471 if (useadsi)
11472 adsi_status(chan, &vms);
11473 break;
11474 default:
11475 ast_test_suite_event_notify("PLAYBACK", "Message: instructions");
11476 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent);
11477 break;
11478 }
11479 }
11480 if ((cmd == 't') || (cmd == '#')) {
11481
11482 res = 0;
11483 } else {
11484
11485 res = -1;
11486 }
11487
11488 out:
11489 if (res > -1) {
11490 ast_stopstream(chan);
11491 adsi_goodbye(chan);
11492 if (valid && res != OPERATOR_EXIT) {
11493 if (silentexit)
11494 res = ast_play_and_wait(chan, "vm-dialout");
11495 else
11496 res = ast_play_and_wait(chan, "vm-goodbye");
11497 }
11498 if ((valid && res > 0) || res == OPERATOR_EXIT) {
11499 res = 0;
11500 }
11501 if (useadsi)
11502 ast_adsi_unload_session(chan);
11503 }
11504 if (vmu)
11505 close_mailbox(&vms, vmu);
11506 if (valid) {
11507 int new = 0, old = 0, urgent = 0;
11508 snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
11509
11510
11511
11512
11513
11514 ast_manager_event(chan, EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL));
11515
11516 run_externnotify(vmu->context, vmu->mailbox, NULL);
11517 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
11518 queue_mwi_event(ext_context, urgent, new, old);
11519 }
11520 #ifdef IMAP_STORAGE
11521
11522 ast_debug(3, "*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
11523 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
11524 ast_mutex_lock(&vms.lock);
11525 #ifdef HAVE_IMAP_TK2006
11526 if (LEVELUIDPLUS (vms.mailstream)) {
11527 mail_expunge_full(vms.mailstream, NIL, EX_UID);
11528 } else
11529 #endif
11530 mail_expunge(vms.mailstream);
11531 ast_mutex_unlock(&vms.lock);
11532 }
11533
11534
11535 if (vmu) {
11536 vmstate_delete(&vms);
11537 }
11538 #endif
11539 if (vmu)
11540 free_user(vmu);
11541
11542 #ifdef IMAP_STORAGE
11543 pthread_setspecific(ts_vmstate.key, NULL);
11544 #endif
11545 return res;
11546 }
11547
11548 static int vm_exec(struct ast_channel *chan, const char *data)
11549 {
11550 int res = 0;
11551 char *tmp;
11552 struct leave_vm_options leave_options;
11553 struct ast_flags flags = { 0 };
11554 char *opts[OPT_ARG_ARRAY_SIZE];
11555 AST_DECLARE_APP_ARGS(args,
11556 AST_APP_ARG(argv0);
11557 AST_APP_ARG(argv1);
11558 );
11559
11560 memset(&leave_options, 0, sizeof(leave_options));
11561
11562 if (ast_channel_state(chan) != AST_STATE_UP)
11563 ast_answer(chan);
11564
11565 if (!ast_strlen_zero(data)) {
11566 tmp = ast_strdupa(data);
11567 AST_STANDARD_APP_ARGS(args, tmp);
11568 if (args.argc == 2) {
11569 if (ast_app_parse_options(vm_app_options, &flags, opts, args.argv1))
11570 return -1;
11571 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
11572 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
11573 int gain;
11574
11575 if (sscanf(opts[OPT_ARG_RECORDGAIN], "%30d", &gain) != 1) {
11576 ast_log(AST_LOG_WARNING, "Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
11577 return -1;
11578 } else {
11579 leave_options.record_gain = (signed char) gain;
11580 }
11581 }
11582 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
11583 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
11584 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
11585 }
11586 }
11587 } else {
11588 char temp[256];
11589 res = ast_app_getdata(chan, "vm-whichbox", temp, sizeof(temp) - 1, 0);
11590 if (res < 0)
11591 return res;
11592 if (ast_strlen_zero(temp))
11593 return 0;
11594 args.argv0 = ast_strdupa(temp);
11595 }
11596
11597 res = leave_voicemail(chan, args.argv0, &leave_options);
11598 if (res == 't') {
11599 ast_play_and_wait(chan, "vm-goodbye");
11600 res = 0;
11601 }
11602
11603 if (res == OPERATOR_EXIT) {
11604 res = 0;
11605 }
11606
11607 if (res == ERROR_LOCK_PATH) {
11608 ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
11609 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
11610 res = 0;
11611 }
11612
11613 return res;
11614 }
11615
11616 static int add_message_id(struct ast_config *msg_cfg, char *dir, int msg, char *filename, char *id, size_t id_size, struct ast_vm_user *vmu, int folder)
11617 {
11618 struct ast_variable *var;
11619 struct ast_category *cat;
11620 generate_msg_id(id);
11621
11622 var = ast_variable_new("msg_id", id, "");
11623 if (!var) {
11624 return -1;
11625 }
11626
11627 cat = ast_category_get(msg_cfg, "message");
11628 if (!cat) {
11629 ast_log(LOG_ERROR, "Voicemail data file %s/%d.txt has no [message] category?\n", dir, msg);
11630 ast_variables_destroy(var);
11631 return -1;
11632 }
11633
11634 ast_variable_append(cat, var);
11635
11636 if (ast_config_text_file_save(filename, msg_cfg, "app_voicemail")) {
11637 ast_log(LOG_WARNING, "Unable to update %s to have a message ID\n", filename);
11638 return -1;
11639 }
11640
11641 UPDATE_MSG_ID(dir, msg, id, vmu, msg_cfg, folder);
11642 return 0;
11643 }
11644
11645 static struct ast_vm_user *find_or_create(const char *context, const char *box)
11646 {
11647 struct ast_vm_user *vmu;
11648
11649 if (!ast_strlen_zero(box) && box[0] == '*') {
11650 ast_log(LOG_WARNING, "Mailbox %s in context %s begins with '*' character. The '*' character,"
11651 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
11652 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
11653 "\n\tand will be ignored.\n", box, context);
11654 return NULL;
11655 }
11656
11657 AST_LIST_TRAVERSE(&users, vmu, list) {
11658 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(box, vmu->mailbox)) {
11659 if (strcasecmp(vmu->context, context)) {
11660 ast_log(LOG_WARNING, "\nIt has been detected that you have defined mailbox '%s' in separate\
11661 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
11662 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
11663 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
11664 }
11665 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s\n", box);
11666 return NULL;
11667 }
11668 if (!strcasecmp(context, vmu->context) && !strcasecmp(box, vmu->mailbox)) {
11669 ast_log(LOG_WARNING, "Ignoring duplicated mailbox %s in context %s\n", box, context);
11670 return NULL;
11671 }
11672 }
11673
11674 if (!(vmu = ast_calloc(1, sizeof(*vmu))))
11675 return NULL;
11676
11677 ast_copy_string(vmu->context, context, sizeof(vmu->context));
11678 ast_copy_string(vmu->mailbox, box, sizeof(vmu->mailbox));
11679
11680 AST_LIST_INSERT_TAIL(&users, vmu, list);
11681
11682 return vmu;
11683 }
11684
11685 static int append_mailbox(const char *context, const char *box, const char *data)
11686 {
11687
11688 char *tmp;
11689 char *stringp;
11690 char *s;
11691 struct ast_vm_user *vmu;
11692 char *mailbox_full;
11693 int new = 0, old = 0, urgent = 0;
11694 char secretfn[PATH_MAX] = "";
11695
11696 tmp = ast_strdupa(data);
11697
11698 if (!(vmu = find_or_create(context, box)))
11699 return -1;
11700
11701 populate_defaults(vmu);
11702
11703 stringp = tmp;
11704 if ((s = strsep(&stringp, ","))) {
11705 if (!ast_strlen_zero(s) && s[0] == '*') {
11706 ast_log(LOG_WARNING, "Invalid password detected for mailbox %s. The password"
11707 "\n\tmust be reset in voicemail.conf.\n", box);
11708 }
11709
11710 ast_copy_string(vmu->password, s, sizeof(vmu->password));
11711 }
11712 if (stringp && (s = strsep(&stringp, ","))) {
11713 ast_copy_string(vmu->fullname, s, sizeof(vmu->fullname));
11714 }
11715 if (stringp && (s = strsep(&stringp, ","))) {
11716 ast_copy_string(vmu->email, s, sizeof(vmu->email));
11717 }
11718 if (stringp && (s = strsep(&stringp, ","))) {
11719 ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
11720 }
11721 if (stringp && (s = strsep(&stringp, ","))) {
11722 apply_options(vmu, s);
11723 }
11724
11725 switch (vmu->passwordlocation) {
11726 case OPT_PWLOC_SPOOLDIR:
11727 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->context, vmu->mailbox);
11728 read_password_from_file(secretfn, vmu->password, sizeof(vmu->password));
11729 }
11730
11731 mailbox_full = ast_alloca(strlen(box) + strlen(context) + 1);
11732 strcpy(mailbox_full, box);
11733 strcat(mailbox_full, "@");
11734 strcat(mailbox_full, context);
11735
11736 inboxcount2(mailbox_full, &urgent, &new, &old);
11737 queue_mwi_event(mailbox_full, urgent, new, old);
11738
11739 return 0;
11740 }
11741
11742 AST_TEST_DEFINE(test_voicemail_vmuser)
11743 {
11744 int res = 0;
11745 struct ast_vm_user *vmu;
11746
11747 static const char options_string[] = "attach=yes|attachfmt=wav49|"
11748 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
11749 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
11750 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
11751 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
11752 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
11753 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
11754 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
11755 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
11756 #ifdef IMAP_STORAGE
11757 static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
11758 "imapfolder=INBOX|imapvmshareid=6000|imapserver=imapserver|imapport=1234|imapflags=flagged";
11759 #endif
11760
11761 switch (cmd) {
11762 case TEST_INIT:
11763 info->name = "vmuser";
11764 info->category = "/apps/app_voicemail/";
11765 info->summary = "Vmuser unit test";
11766 info->description =
11767 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
11768 return AST_TEST_NOT_RUN;
11769 case TEST_EXECUTE:
11770 break;
11771 }
11772
11773 if (!(vmu = ast_calloc(1, sizeof(*vmu)))) {
11774 return AST_TEST_NOT_RUN;
11775 }
11776 populate_defaults(vmu);
11777 ast_set_flag(vmu, VM_ALLOCED);
11778
11779 apply_options(vmu, options_string);
11780
11781 if (!ast_test_flag(vmu, VM_ATTACH)) {
11782 ast_test_status_update(test, "Parse failure for attach option\n");
11783 res = 1;
11784 }
11785 if (strcasecmp(vmu->attachfmt, "wav49")) {
11786 ast_test_status_update(test, "Parse failure for attachftm option\n");
11787 res = 1;
11788 }
11789 if (strcasecmp(vmu->serveremail, "someguy@digium.com")) {
11790 ast_test_status_update(test, "Parse failure for serveremail option\n");
11791 res = 1;
11792 }
11793 if (!vmu->emailsubject || strcasecmp(vmu->emailsubject, "[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
11794 ast_test_status_update(test, "Parse failure for emailsubject option\n");
11795 res = 1;
11796 }
11797 if (!vmu->emailbody || strcasecmp(vmu->emailbody, "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
11798 ast_test_status_update(test, "Parse failure for emailbody option\n");
11799 res = 1;
11800 }
11801 if (strcasecmp(vmu->zonetag, "central")) {
11802 ast_test_status_update(test, "Parse failure for tz option\n");
11803 res = 1;
11804 }
11805 if (!ast_test_flag(vmu, VM_DELETE)) {
11806 ast_test_status_update(test, "Parse failure for delete option\n");
11807 res = 1;
11808 }
11809 if (!ast_test_flag(vmu, VM_SAYCID)) {
11810 ast_test_status_update(test, "Parse failure for saycid option\n");
11811 res = 1;
11812 }
11813 if (!ast_test_flag(vmu, VM_SVMAIL)) {
11814 ast_test_status_update(test, "Parse failure for sendvoicemail option\n");
11815 res = 1;
11816 }
11817 if (!ast_test_flag(vmu, VM_REVIEW)) {
11818 ast_test_status_update(test, "Parse failure for review option\n");
11819 res = 1;
11820 }
11821 if (!ast_test_flag(vmu, VM_TEMPGREETWARN)) {
11822 ast_test_status_update(test, "Parse failure for tempgreetwarm option\n");
11823 res = 1;
11824 }
11825 if (!ast_test_flag(vmu, VM_MESSAGEWRAP)) {
11826 ast_test_status_update(test, "Parse failure for messagewrap option\n");
11827 res = 1;
11828 }
11829 if (!ast_test_flag(vmu, VM_OPERATOR)) {
11830 ast_test_status_update(test, "Parse failure for operator option\n");
11831 res = 1;
11832 }
11833 if (!ast_test_flag(vmu, VM_ENVELOPE)) {
11834 ast_test_status_update(test, "Parse failure for envelope option\n");
11835 res = 1;
11836 }
11837 if (!ast_test_flag(vmu, VM_MOVEHEARD)) {
11838 ast_test_status_update(test, "Parse failure for moveheard option\n");
11839 res = 1;
11840 }
11841 if (!ast_test_flag(vmu, VM_SAYDURATION)) {
11842 ast_test_status_update(test, "Parse failure for sayduration option\n");
11843 res = 1;
11844 }
11845 if (vmu->saydurationm != 5) {
11846 ast_test_status_update(test, "Parse failure for saydurationm option\n");
11847 res = 1;
11848 }
11849 if (!ast_test_flag(vmu, VM_FORCENAME)) {
11850 ast_test_status_update(test, "Parse failure for forcename option\n");
11851 res = 1;
11852 }
11853 if (!ast_test_flag(vmu, VM_FORCEGREET)) {
11854 ast_test_status_update(test, "Parse failure for forcegreetings option\n");
11855 res = 1;
11856 }
11857 if (strcasecmp(vmu->callback, "somecontext")) {
11858 ast_test_status_update(test, "Parse failure for callbacks option\n");
11859 res = 1;
11860 }
11861 if (strcasecmp(vmu->dialout, "somecontext2")) {
11862 ast_test_status_update(test, "Parse failure for dialout option\n");
11863 res = 1;
11864 }
11865 if (strcasecmp(vmu->exit, "somecontext3")) {
11866 ast_test_status_update(test, "Parse failure for exitcontext option\n");
11867 res = 1;
11868 }
11869 if (vmu->minsecs != 10) {
11870 ast_test_status_update(test, "Parse failure for minsecs option\n");
11871 res = 1;
11872 }
11873 if (vmu->maxsecs != 100) {
11874 ast_test_status_update(test, "Parse failure for maxsecs option\n");
11875 res = 1;
11876 }
11877 if (!ast_test_flag(vmu, VM_SKIPAFTERCMD)) {
11878 ast_test_status_update(test, "Parse failure for nextaftercmd option\n");
11879 res = 1;
11880 }
11881 if (vmu->maxdeletedmsg != 50) {
11882 ast_test_status_update(test, "Parse failure for backupdeleted option\n");
11883 res = 1;
11884 }
11885 if (vmu->volgain != 1.3) {
11886 ast_test_status_update(test, "Parse failure for volgain option\n");
11887 res = 1;
11888 }
11889 if (vmu->passwordlocation != OPT_PWLOC_SPOOLDIR) {
11890 ast_test_status_update(test, "Parse failure for passwordlocation option\n");
11891 res = 1;
11892 }
11893 #ifdef IMAP_STORAGE
11894 apply_options(vmu, option_string2);
11895
11896 if (strcasecmp(vmu->imapuser, "imapuser")) {
11897 ast_test_status_update(test, "Parse failure for imapuser option\n");
11898 res = 1;
11899 }
11900 if (strcasecmp(vmu->imappassword, "imappasswd")) {
11901 ast_test_status_update(test, "Parse failure for imappasswd option\n");
11902 res = 1;
11903 }
11904 if (strcasecmp(vmu->imapfolder, "INBOX")) {
11905 ast_test_status_update(test, "Parse failure for imapfolder option\n");
11906 res = 1;
11907 }
11908 if (strcasecmp(vmu->imapvmshareid, "6000")) {
11909 ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
11910 res = 1;
11911 }
11912 if (strcasecmp(vmu->imapserver, "imapserver")) {
11913 ast_test_status_update(test, "Parse failure for imapserver option\n");
11914 res = 1;
11915 }
11916 if (strcasecmp(vmu->imapport, "1234")) {
11917 ast_test_status_update(test, "Parse failure for imapport option\n");
11918 res = 1;
11919 }
11920 if (strcasecmp(vmu->imapflags, "flagged")) {
11921 ast_test_status_update(test, "Parse failure for imapflags option\n");
11922 res = 1;
11923 }
11924 #endif
11925
11926 free_user(vmu);
11927 return res ? AST_TEST_FAIL : AST_TEST_PASS;
11928 }
11929
11930 static int vm_box_exists(struct ast_channel *chan, const char *data)
11931 {
11932 struct ast_vm_user svm;
11933 char *context, *box;
11934 AST_DECLARE_APP_ARGS(args,
11935 AST_APP_ARG(mbox);
11936 AST_APP_ARG(options);
11937 );
11938 static int dep_warning = 0;
11939
11940 if (ast_strlen_zero(data)) {
11941 ast_log(AST_LOG_ERROR, "MailboxExists requires an argument: (vmbox[@context][|options])\n");
11942 return -1;
11943 }
11944
11945 if (!dep_warning) {
11946 dep_warning = 1;
11947 ast_log(AST_LOG_WARNING, "MailboxExists is deprecated. Please use ${VM_INFO(%s,exists)} instead.\n", data);
11948 }
11949
11950 box = ast_strdupa(data);
11951
11952 AST_STANDARD_APP_ARGS(args, box);
11953
11954 if (args.options) {
11955 }
11956
11957 if ((context = strchr(args.mbox, '@'))) {
11958 *context = '\0';
11959 context++;
11960 }
11961
11962 if (find_user(&svm, context, args.mbox)) {
11963 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "SUCCESS");
11964 } else
11965 pbx_builtin_setvar_helper(chan, "VMBOXEXISTSSTATUS", "FAILED");
11966
11967 return 0;
11968 }
11969
11970 static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
11971 {
11972 struct ast_vm_user svm;
11973 AST_DECLARE_APP_ARGS(arg,
11974 AST_APP_ARG(mbox);
11975 AST_APP_ARG(context);
11976 );
11977 static int dep_warning = 0;
11978
11979 AST_NONSTANDARD_APP_ARGS(arg, args, '@');
11980
11981 if (ast_strlen_zero(arg.mbox)) {
11982 ast_log(LOG_ERROR, "MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11983 return -1;
11984 }
11985
11986 if (!dep_warning) {
11987 dep_warning = 1;
11988 ast_log(AST_LOG_WARNING, "MAILBOX_EXISTS is deprecated. Please use ${VM_INFO(%s,exists)} instead.\n", args);
11989 }
11990
11991 ast_copy_string(buf, find_user(&svm, ast_strlen_zero(arg.context) ? "default" : arg.context, arg.mbox) ? "1" : "0", len);
11992 return 0;
11993 }
11994
11995 static int acf_vm_info(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
11996 {
11997 struct ast_vm_user svm;
11998 struct ast_vm_user *vmu = NULL;
11999 char *tmp, *mailbox, *context, *parse;
12000 int res = 0;
12001
12002 AST_DECLARE_APP_ARGS(arg,
12003 AST_APP_ARG(mailbox_context);
12004 AST_APP_ARG(attribute);
12005 AST_APP_ARG(folder);
12006 );
12007
12008 buf[0] = '\0';
12009
12010 if (ast_strlen_zero(args)) {
12011 ast_log(LOG_ERROR, "VM_INFO requires an argument (<mailbox>[@<context>],attribute[,folder])\n");
12012 return -1;
12013 }
12014
12015 parse = ast_strdupa(args);
12016 AST_STANDARD_APP_ARGS(arg, parse);
12017
12018 if (ast_strlen_zero(arg.mailbox_context) || ast_strlen_zero(arg.attribute)) {
12019 ast_log(LOG_ERROR, "VM_INFO requires an argument (<mailbox>[@<context>],attribute[,folder])\n");
12020 return -1;
12021 }
12022
12023 tmp = ast_strdupa(arg.mailbox_context);
12024 mailbox = strsep(&tmp, "@");
12025 context = strsep(&tmp, "");
12026
12027 if (ast_strlen_zero(context)) {
12028 context = "default";
12029 }
12030
12031 vmu = find_user(&svm, context, mailbox);
12032
12033 if (!strncasecmp(arg.attribute, "exists", 5)) {
12034 ast_copy_string(buf, vmu ? "1" : "0", len);
12035 return 0;
12036 }
12037
12038 if (vmu) {
12039 if (!strncasecmp(arg.attribute, "password", 8)) {
12040 ast_copy_string(buf, vmu->password, len);
12041 } else if (!strncasecmp(arg.attribute, "fullname", 8)) {
12042 ast_copy_string(buf, vmu->fullname, len);
12043 } else if (!strncasecmp(arg.attribute, "email", 5)) {
12044 ast_copy_string(buf, vmu->email, len);
12045 } else if (!strncasecmp(arg.attribute, "pager", 5)) {
12046 ast_copy_string(buf, vmu->pager, len);
12047 } else if (!strncasecmp(arg.attribute, "language", 8)) {
12048 const char *lang = S_OR(vmu->language, chan ?
12049 ast_channel_language(chan) : ast_defaultlanguage);
12050 ast_copy_string(buf, lang, len);
12051 } else if (!strncasecmp(arg.attribute, "locale", 6)) {
12052 ast_copy_string(buf, vmu->locale, len);
12053 } else if (!strncasecmp(arg.attribute, "tz", 2)) {
12054 ast_copy_string(buf, vmu->zonetag, len);
12055 } else if (!strncasecmp(arg.attribute, "count", 5)) {
12056
12057 res = messagecount(context, mailbox, arg.folder);
12058 if (res < 0) {
12059 ast_log(LOG_ERROR, "Unable to retrieve message count for mailbox %s\n", arg.mailbox_context);
12060 return -1;
12061 }
12062 snprintf(buf, len, "%d", res);
12063 } else {
12064 ast_log(LOG_ERROR, "Unknown attribute '%s' for VM_INFO\n", arg.attribute);
12065 return -1;
12066 }
12067 }
12068
12069 return 0;
12070 }
12071
12072 static struct ast_custom_function mailbox_exists_acf = {
12073 .name = "MAILBOX_EXISTS",
12074 .read = acf_mailbox_exists,
12075 };
12076
12077 static struct ast_custom_function vm_info_acf = {
12078 .name = "VM_INFO",
12079 .read = acf_vm_info,
12080 };
12081
12082 static int vmauthenticate(struct ast_channel *chan, const char *data)
12083 {
12084 char *s, *user = NULL, *context = NULL, mailbox[AST_MAX_EXTENSION] = "";
12085 struct ast_vm_user vmus;
12086 char *options = NULL;
12087 int silent = 0, skipuser = 0;
12088 int res = -1;
12089
12090 if (data) {
12091 s = ast_strdupa(data);
12092 user = strsep(&s, ",");
12093 options = strsep(&s, ",");
12094 if (user) {
12095 s = user;
12096 user = strsep(&s, "@");
12097 context = strsep(&s, "");
12098 if (!ast_strlen_zero(user))
12099 skipuser++;
12100 ast_copy_string(mailbox, user, sizeof(mailbox));
12101 }
12102 }
12103
12104 if (options) {
12105 silent = (strchr(options, 's')) != NULL;
12106 }
12107
12108 if (!vm_authenticate(chan, mailbox, sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
12109 pbx_builtin_setvar_helper(chan, "AUTH_MAILBOX", mailbox);
12110 pbx_builtin_setvar_helper(chan, "AUTH_CONTEXT", vmus.context);
12111 ast_play_and_wait(chan, "auth-thankyou");
12112 res = 0;
12113 } else if (mailbox[0] == '*') {
12114
12115 if (!ast_goto_if_exists(chan, ast_channel_context(chan), "a", 1)) {
12116 res = 0;
12117 }
12118 }
12119
12120 return res;
12121 }
12122
12123 static char *show_users_realtime(int fd, const char *context)
12124 {
12125 struct ast_config *cfg;
12126 const char *cat = NULL;
12127
12128 if (!(cfg = ast_load_realtime_multientry("voicemail",
12129 "context", context, SENTINEL))) {
12130 return CLI_FAILURE;
12131 }
12132
12133 ast_cli(fd,
12134 "\n"
12135 "=============================================================\n"
12136 "=== Configured Voicemail Users ==============================\n"
12137 "=============================================================\n"
12138 "===\n");
12139
12140 while ((cat = ast_category_browse(cfg, cat))) {
12141 struct ast_variable *var = NULL;
12142 ast_cli(fd,
12143 "=== Mailbox ...\n"
12144 "===\n");
12145 for (var = ast_variable_browse(cfg, cat); var; var = var->next)
12146 ast_cli(fd, "=== ==> %s: %s\n", var->name, var->value);
12147 ast_cli(fd,
12148 "===\n"
12149 "=== ---------------------------------------------------------\n"
12150 "===\n");
12151 }
12152
12153 ast_cli(fd,
12154 "=============================================================\n"
12155 "\n");
12156
12157 ast_config_destroy(cfg);
12158
12159 return CLI_SUCCESS;
12160 }
12161
12162 static char *complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
12163 {
12164 int which = 0;
12165 int wordlen;
12166 struct ast_vm_user *vmu;
12167 const char *context = "";
12168
12169
12170 if (pos > 4)
12171 return NULL;
12172 if (pos == 3)
12173 return (state == 0) ? ast_strdup("for") : NULL;
12174 wordlen = strlen(word);
12175 AST_LIST_TRAVERSE(&users, vmu, list) {
12176 if (!strncasecmp(word, vmu->context, wordlen)) {
12177 if (context && strcmp(context, vmu->context) && ++which > state)
12178 return ast_strdup(vmu->context);
12179
12180 context = vmu->context;
12181 }
12182 }
12183 return NULL;
12184 }
12185
12186
12187 static char *handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12188 {
12189 struct ast_vm_user *vmu;
12190 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
12191 const char *context = NULL;
12192 int users_counter = 0;
12193
12194 switch (cmd) {
12195 case CLI_INIT:
12196 e->command = "voicemail show users";
12197 e->usage =
12198 "Usage: voicemail show users [for <context>]\n"
12199 " Lists all mailboxes currently set up\n";
12200 return NULL;
12201 case CLI_GENERATE:
12202 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
12203 }
12204
12205 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
12206 return CLI_SHOWUSAGE;
12207 if (a->argc == 5) {
12208 if (strcmp(a->argv[3],"for"))
12209 return CLI_SHOWUSAGE;
12210 context = a->argv[4];
12211 }
12212
12213 if (ast_check_realtime("voicemail")) {
12214 if (!context) {
12215 ast_cli(a->fd, "You must specify a specific context to show users from realtime!\n");
12216 return CLI_SHOWUSAGE;
12217 }
12218 return show_users_realtime(a->fd, context);
12219 }
12220
12221 AST_LIST_LOCK(&users);
12222 if (AST_LIST_EMPTY(&users)) {
12223 ast_cli(a->fd, "There are no voicemail users currently defined\n");
12224 AST_LIST_UNLOCK(&users);
12225 return CLI_FAILURE;
12226 }
12227 if (!context) {
12228 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
12229 } else {
12230 int count = 0;
12231 AST_LIST_TRAVERSE(&users, vmu, list) {
12232 if (!strcmp(context, vmu->context)) {
12233 count++;
12234 break;
12235 }
12236 }
12237 if (count) {
12238 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, "Context", "Mbox", "User", "Zone", "NewMsg");
12239 } else {
12240 ast_cli(a->fd, "No such voicemail context \"%s\"\n", context);
12241 AST_LIST_UNLOCK(&users);
12242 return CLI_FAILURE;
12243 }
12244 }
12245 AST_LIST_TRAVERSE(&users, vmu, list) {
12246 int newmsgs = 0, oldmsgs = 0;
12247 char count[12], tmp[256] = "";
12248
12249 if (!context || !strcmp(context, vmu->context)) {
12250 snprintf(tmp, sizeof(tmp), "%s@%s", vmu->mailbox, ast_strlen_zero(vmu->context) ? "default" : vmu->context);
12251 inboxcount(tmp, &newmsgs, &oldmsgs);
12252 snprintf(count, sizeof(count), "%d", newmsgs);
12253 ast_cli(a->fd, HVSU_OUTPUT_FORMAT, vmu->context, vmu->mailbox, vmu->fullname, vmu->zonetag, count);
12254 users_counter++;
12255 }
12256 }
12257 AST_LIST_UNLOCK(&users);
12258 ast_cli(a->fd, "%d voicemail users configured.\n", users_counter);
12259 return CLI_SUCCESS;
12260 }
12261
12262
12263 static char *handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12264 {
12265 struct vm_zone *zone;
12266 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
12267 char *res = CLI_SUCCESS;
12268
12269 switch (cmd) {
12270 case CLI_INIT:
12271 e->command = "voicemail show zones";
12272 e->usage =
12273 "Usage: voicemail show zones\n"
12274 " Lists zone message formats\n";
12275 return NULL;
12276 case CLI_GENERATE:
12277 return NULL;
12278 }
12279
12280 if (a->argc != 3)
12281 return CLI_SHOWUSAGE;
12282
12283 AST_LIST_LOCK(&zones);
12284 if (!AST_LIST_EMPTY(&zones)) {
12285 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, "Zone", "Timezone", "Message Format");
12286 AST_LIST_TRAVERSE(&zones, zone, list) {
12287 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
12288 }
12289 } else {
12290 ast_cli(a->fd, "There are no voicemail zones currently defined\n");
12291 res = CLI_FAILURE;
12292 }
12293 AST_LIST_UNLOCK(&zones);
12294
12295 return res;
12296 }
12297
12298
12299 static char *handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12300 {
12301 switch (cmd) {
12302 case CLI_INIT:
12303 e->command = "voicemail reload";
12304 e->usage =
12305 "Usage: voicemail reload\n"
12306 " Reload voicemail configuration\n";
12307 return NULL;
12308 case CLI_GENERATE:
12309 return NULL;
12310 }
12311
12312 if (a->argc != 2)
12313 return CLI_SHOWUSAGE;
12314
12315 ast_cli(a->fd, "Reloading voicemail configuration...\n");
12316 load_config(1);
12317
12318 return CLI_SUCCESS;
12319 }
12320
12321 static struct ast_cli_entry cli_voicemail[] = {
12322 AST_CLI_DEFINE(handle_voicemail_show_users, "List defined voicemail boxes"),
12323 AST_CLI_DEFINE(handle_voicemail_show_zones, "List zone message formats"),
12324 AST_CLI_DEFINE(handle_voicemail_reload, "Reload voicemail configuration"),
12325 };
12326
12327 #ifdef IMAP_STORAGE
12328 #define DATA_EXPORT_VM_USERS(USER) \
12329 USER(ast_vm_user, context, AST_DATA_STRING) \
12330 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
12331 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
12332 USER(ast_vm_user, fullname, AST_DATA_STRING) \
12333 USER(ast_vm_user, email, AST_DATA_STRING) \
12334 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
12335 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
12336 USER(ast_vm_user, pager, AST_DATA_STRING) \
12337 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
12338 USER(ast_vm_user, language, AST_DATA_STRING) \
12339 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
12340 USER(ast_vm_user, callback, AST_DATA_STRING) \
12341 USER(ast_vm_user, dialout, AST_DATA_STRING) \
12342 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
12343 USER(ast_vm_user, exit, AST_DATA_STRING) \
12344 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
12345 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
12346 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
12347 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
12348 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
12349 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
12350 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
12351 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
12352 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
12353 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
12354 #else
12355 #define DATA_EXPORT_VM_USERS(USER) \
12356 USER(ast_vm_user, context, AST_DATA_STRING) \
12357 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
12358 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
12359 USER(ast_vm_user, fullname, AST_DATA_STRING) \
12360 USER(ast_vm_user, email, AST_DATA_STRING) \
12361 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
12362 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
12363 USER(ast_vm_user, pager, AST_DATA_STRING) \
12364 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
12365 USER(ast_vm_user, language, AST_DATA_STRING) \
12366 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
12367 USER(ast_vm_user, callback, AST_DATA_STRING) \
12368 USER(ast_vm_user, dialout, AST_DATA_STRING) \
12369 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
12370 USER(ast_vm_user, exit, AST_DATA_STRING) \
12371 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
12372 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
12373 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
12374 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
12375 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
12376 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
12377 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
12378 #endif
12379
12380 AST_DATA_STRUCTURE(ast_vm_user, DATA_EXPORT_VM_USERS);
12381
12382 #define DATA_EXPORT_VM_ZONES(ZONE) \
12383 ZONE(vm_zone, name, AST_DATA_STRING) \
12384 ZONE(vm_zone, timezone, AST_DATA_STRING) \
12385 ZONE(vm_zone, msg_format, AST_DATA_STRING)
12386
12387 AST_DATA_STRUCTURE(vm_zone, DATA_EXPORT_VM_ZONES);
12388
12389
12390
12391
12392
12393
12394
12395
12396 static int vm_users_data_provider_get_helper(const struct ast_data_search *search,
12397 struct ast_data *data_root, struct ast_vm_user *user)
12398 {
12399 struct ast_data *data_user, *data_zone;
12400 struct ast_data *data_state;
12401 struct vm_zone *zone = NULL;
12402 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
12403 char ext_context[256] = "";
12404
12405 data_user = ast_data_add_node(data_root, "user");
12406 if (!data_user) {
12407 return -1;
12408 }
12409
12410 ast_data_add_structure(ast_vm_user, data_user, user);
12411
12412 AST_LIST_LOCK(&zones);
12413 AST_LIST_TRAVERSE(&zones, zone, list) {
12414 if (!strcmp(zone->name, user->zonetag)) {
12415 break;
12416 }
12417 }
12418 AST_LIST_UNLOCK(&zones);
12419
12420
12421 data_state = ast_data_add_node(data_user, "state");
12422 if (!data_state) {
12423 return -1;
12424 }
12425 snprintf(ext_context, sizeof(ext_context), "%s@%s", user->mailbox, user->context);
12426 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
12427 ast_data_add_int(data_state, "urgentmsg", urgentmsg);
12428 ast_data_add_int(data_state, "newmsg", newmsg);
12429 ast_data_add_int(data_state, "oldmsg", oldmsg);
12430
12431 if (zone) {
12432 data_zone = ast_data_add_node(data_user, "zone");
12433 ast_data_add_structure(vm_zone, data_zone, zone);
12434 }
12435
12436 if (!ast_data_search_match(search, data_user)) {
12437 ast_data_remove_node(data_root, data_user);
12438 }
12439
12440 return 0;
12441 }
12442
12443 static int vm_users_data_provider_get(const struct ast_data_search *search,
12444 struct ast_data *data_root)
12445 {
12446 struct ast_vm_user *user;
12447
12448 AST_LIST_LOCK(&users);
12449 AST_LIST_TRAVERSE(&users, user, list) {
12450 vm_users_data_provider_get_helper(search, data_root, user);
12451 }
12452 AST_LIST_UNLOCK(&users);
12453
12454 return 0;
12455 }
12456
12457 static const struct ast_data_handler vm_users_data_provider = {
12458 .version = AST_DATA_HANDLER_VERSION,
12459 .get = vm_users_data_provider_get
12460 };
12461
12462 static const struct ast_data_entry vm_data_providers[] = {
12463 AST_DATA_ENTRY("asterisk/application/voicemail/list", &vm_users_data_provider)
12464 };
12465
12466 static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
12467 {
12468 int new = 0, old = 0, urgent = 0;
12469
12470 inboxcount2(mwi_sub->mailbox, &urgent, &new, &old);
12471
12472 if (urgent != mwi_sub->old_urgent || new != mwi_sub->old_new || old != mwi_sub->old_old) {
12473 mwi_sub->old_urgent = urgent;
12474 mwi_sub->old_new = new;
12475 mwi_sub->old_old = old;
12476 queue_mwi_event(mwi_sub->mailbox, urgent, new, old);
12477 run_externnotify(NULL, mwi_sub->mailbox, NULL);
12478 }
12479 }
12480
12481 static void poll_subscribed_mailboxes(void)
12482 {
12483 struct mwi_sub *mwi_sub;
12484
12485 AST_RWLIST_RDLOCK(&mwi_subs);
12486 AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
12487 if (!ast_strlen_zero(mwi_sub->mailbox)) {
12488 poll_subscribed_mailbox(mwi_sub);
12489 }
12490 }
12491 AST_RWLIST_UNLOCK(&mwi_subs);
12492 }
12493
12494 static void *mb_poll_thread(void *data)
12495 {
12496 while (poll_thread_run) {
12497 struct timespec ts = { 0, };
12498 struct timeval wait;
12499
12500 wait = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
12501 ts.tv_sec = wait.tv_sec;
12502 ts.tv_nsec = wait.tv_usec * 1000;
12503
12504 ast_mutex_lock(&poll_lock);
12505 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
12506 ast_mutex_unlock(&poll_lock);
12507
12508 if (!poll_thread_run)
12509 break;
12510
12511 poll_subscribed_mailboxes();
12512 }
12513
12514 return NULL;
12515 }
12516
12517 static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
12518 {
12519 ast_free(mwi_sub);
12520 }
12521
12522 static int handle_unsubscribe(void *datap)
12523 {
12524 struct mwi_sub *mwi_sub;
12525 uint32_t *uniqueid = datap;
12526
12527 AST_RWLIST_WRLOCK(&mwi_subs);
12528 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
12529 if (mwi_sub->uniqueid == *uniqueid) {
12530 AST_LIST_REMOVE_CURRENT(entry);
12531 break;
12532 }
12533 }
12534 AST_RWLIST_TRAVERSE_SAFE_END
12535 AST_RWLIST_UNLOCK(&mwi_subs);
12536
12537 if (mwi_sub)
12538 mwi_sub_destroy(mwi_sub);
12539
12540 ast_free(uniqueid);
12541 return 0;
12542 }
12543
12544 static int handle_subscribe(void *datap)
12545 {
12546 unsigned int len;
12547 struct mwi_sub *mwi_sub;
12548 struct mwi_sub_task *p = datap;
12549
12550 len = sizeof(*mwi_sub);
12551 if (!ast_strlen_zero(p->mailbox))
12552 len += strlen(p->mailbox);
12553
12554 if (!ast_strlen_zero(p->context))
12555 len += strlen(p->context) + 1;
12556
12557 if (!(mwi_sub = ast_calloc(1, len)))
12558 return -1;
12559
12560 mwi_sub->uniqueid = p->uniqueid;
12561 if (!ast_strlen_zero(p->mailbox))
12562 strcpy(mwi_sub->mailbox, p->mailbox);
12563
12564 if (!ast_strlen_zero(p->context)) {
12565 strcat(mwi_sub->mailbox, "@");
12566 strcat(mwi_sub->mailbox, p->context);
12567 }
12568
12569 AST_RWLIST_WRLOCK(&mwi_subs);
12570 AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
12571 AST_RWLIST_UNLOCK(&mwi_subs);
12572 ast_free((void *) p->mailbox);
12573 ast_free((void *) p->context);
12574 ast_free(p);
12575 poll_subscribed_mailbox(mwi_sub);
12576 return 0;
12577 }
12578
12579 static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
12580 {
12581 uint32_t u, *uniqueid = ast_calloc(1, sizeof(*uniqueid));
12582
12583 if (!uniqueid) {
12584 ast_log(LOG_ERROR, "Unable to allocate memory for uniqueid\n");
12585 return;
12586 }
12587
12588 if (ast_event_get_type(event) != AST_EVENT_UNSUB) {
12589 ast_free(uniqueid);
12590 return;
12591 }
12592
12593 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI) {
12594 ast_free(uniqueid);
12595 return;
12596 }
12597
12598 u = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
12599 *uniqueid = u;
12600 if (ast_taskprocessor_push(mwi_subscription_tps, handle_unsubscribe, uniqueid) < 0) {
12601 ast_free(uniqueid);
12602 }
12603 }
12604
12605 static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
12606 {
12607 struct mwi_sub_task *mwist;
12608
12609 if (ast_event_get_type(event) != AST_EVENT_SUB)
12610 return;
12611
12612 if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
12613 return;
12614
12615 if ((mwist = ast_calloc(1, (sizeof(*mwist)))) == NULL) {
12616 ast_log(LOG_ERROR, "could not allocate a mwi_sub_task\n");
12617 return;
12618 }
12619 mwist->mailbox = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX));
12620 mwist->context = ast_strdup(ast_event_get_ie_str(event, AST_EVENT_IE_CONTEXT));
12621 mwist->uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
12622
12623 if (ast_taskprocessor_push(mwi_subscription_tps, handle_subscribe, mwist) < 0) {
12624 ast_free(mwist);
12625 }
12626 }
12627
12628 static void start_poll_thread(void)
12629 {
12630 int errcode;
12631 mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, "Voicemail MWI subscription", NULL,
12632 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
12633 AST_EVENT_IE_END);
12634
12635 mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, "Voicemail MWI subscription", NULL,
12636 AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
12637 AST_EVENT_IE_END);
12638
12639 if (mwi_sub_sub)
12640 ast_event_report_subs(mwi_sub_sub);
12641
12642 poll_thread_run = 1;
12643
12644 if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL))) {
12645 ast_log(LOG_ERROR, "Could not create thread: %s\n", strerror(errcode));
12646 }
12647 }
12648
12649 static void stop_poll_thread(void)
12650 {
12651 poll_thread_run = 0;
12652
12653 if (mwi_sub_sub) {
12654 ast_event_unsubscribe(mwi_sub_sub);
12655 mwi_sub_sub = NULL;
12656 }
12657
12658 if (mwi_unsub_sub) {
12659 ast_event_unsubscribe(mwi_unsub_sub);
12660 mwi_unsub_sub = NULL;
12661 }
12662
12663 ast_mutex_lock(&poll_lock);
12664 ast_cond_signal(&poll_cond);
12665 ast_mutex_unlock(&poll_lock);
12666
12667 pthread_join(poll_thread, NULL);
12668
12669 poll_thread = AST_PTHREADT_NULL;
12670 }
12671
12672
12673 static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
12674 {
12675 struct ast_vm_user *vmu = NULL;
12676 const char *id = astman_get_header(m, "ActionID");
12677 char actionid[128] = "";
12678
12679 if (!ast_strlen_zero(id))
12680 snprintf(actionid, sizeof(actionid), "ActionID: %s\r\n", id);
12681
12682 AST_LIST_LOCK(&users);
12683
12684 if (AST_LIST_EMPTY(&users)) {
12685 astman_send_ack(s, m, "There are no voicemail users currently defined.");
12686 AST_LIST_UNLOCK(&users);
12687 return RESULT_SUCCESS;
12688 }
12689
12690 astman_send_ack(s, m, "Voicemail user list will follow");
12691
12692 AST_LIST_TRAVERSE(&users, vmu, list) {
12693 char dirname[256];
12694
12695 #ifdef IMAP_STORAGE
12696 int new, old;
12697 inboxcount(vmu->mailbox, &new, &old);
12698 #endif
12699
12700 make_dir(dirname, sizeof(dirname), vmu->context, vmu->mailbox, "INBOX");
12701 astman_append(s,
12702 "%s"
12703 "Event: VoicemailUserEntry\r\n"
12704 "VMContext: %s\r\n"
12705 "VoiceMailbox: %s\r\n"
12706 "Fullname: %s\r\n"
12707 "Email: %s\r\n"
12708 "Pager: %s\r\n"
12709 "ServerEmail: %s\r\n"
12710 "MailCommand: %s\r\n"
12711 "Language: %s\r\n"
12712 "TimeZone: %s\r\n"
12713 "Callback: %s\r\n"
12714 "Dialout: %s\r\n"
12715 "UniqueID: %s\r\n"
12716 "ExitContext: %s\r\n"
12717 "SayDurationMinimum: %d\r\n"
12718 "SayEnvelope: %s\r\n"
12719 "SayCID: %s\r\n"
12720 "AttachMessage: %s\r\n"
12721 "AttachmentFormat: %s\r\n"
12722 "DeleteMessage: %s\r\n"
12723 "VolumeGain: %.2f\r\n"
12724 "CanReview: %s\r\n"
12725 "CallOperator: %s\r\n"
12726 "MaxMessageCount: %d\r\n"
12727 "MaxMessageLength: %d\r\n"
12728 "NewMessageCount: %d\r\n"
12729 #ifdef IMAP_STORAGE
12730 "OldMessageCount: %d\r\n"
12731 "IMAPUser: %s\r\n"
12732 "IMAPServer: %s\r\n"
12733 "IMAPPort: %s\r\n"
12734 "IMAPFlags: %s\r\n"
12735 #endif
12736 "\r\n",
12737 actionid,
12738 vmu->context,
12739 vmu->mailbox,
12740 vmu->fullname,
12741 vmu->email,
12742 vmu->pager,
12743 ast_strlen_zero(vmu->serveremail) ? serveremail : vmu->serveremail,
12744 mailcmd,
12745 vmu->language,
12746 vmu->zonetag,
12747 vmu->callback,
12748 vmu->dialout,
12749 vmu->uniqueid,
12750 vmu->exit,
12751 vmu->saydurationm,
12752 ast_test_flag(vmu, VM_ENVELOPE) ? "Yes" : "No",
12753 ast_test_flag(vmu, VM_SAYCID) ? "Yes" : "No",
12754 ast_test_flag(vmu, VM_ATTACH) ? "Yes" : "No",
12755 vmu->attachfmt,
12756 ast_test_flag(vmu, VM_DELETE) ? "Yes" : "No",
12757 vmu->volgain,
12758 ast_test_flag(vmu, VM_REVIEW) ? "Yes" : "No",
12759 ast_test_flag(vmu, VM_OPERATOR) ? "Yes" : "No",
12760 vmu->maxmsg,
12761 vmu->maxsecs,
12762 #ifdef IMAP_STORAGE
12763 new, old,
12764 vmu->imapuser,
12765 vmu->imapserver,
12766 vmu->imapport,
12767 vmu->imapflags
12768 #else
12769 count_messages(vmu, dirname)
12770 #endif
12771 );
12772 }
12773 astman_append(s, "Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
12774
12775 AST_LIST_UNLOCK(&users);
12776
12777 return RESULT_SUCCESS;
12778 }
12779
12780
12781 static void free_vm_users(void)
12782 {
12783 struct ast_vm_user *current;
12784 AST_LIST_LOCK(&users);
12785 while ((current = AST_LIST_REMOVE_HEAD(&users, list))) {
12786 ast_set_flag(current, VM_ALLOCED);
12787 free_user(current);
12788 }
12789 AST_LIST_UNLOCK(&users);
12790 }
12791
12792
12793 static void free_vm_zones(void)
12794 {
12795 struct vm_zone *zcur;
12796 AST_LIST_LOCK(&zones);
12797 while ((zcur = AST_LIST_REMOVE_HEAD(&zones, list)))
12798 free_zone(zcur);
12799 AST_LIST_UNLOCK(&zones);
12800 }
12801
12802 static const char *substitute_escapes(const char *value)
12803 {
12804 char *current;
12805
12806
12807 struct ast_str *str = ast_str_thread_get(&ast_str_thread_global_buf, strlen(value) + 16);
12808
12809 ast_str_reset(str);
12810
12811
12812 for (current = (char *) value; *current; current++) {
12813 if (*current == '\\') {
12814 current++;
12815 if (!*current) {
12816 ast_log(AST_LOG_NOTICE, "Incomplete escape at end of value.\n");
12817 break;
12818 }
12819 switch (*current) {
12820 case '\\':
12821 ast_str_append(&str, 0, "\\");
12822 break;
12823 case 'r':
12824 ast_str_append(&str, 0, "\r");
12825 break;
12826 case 'n':
12827 #ifdef IMAP_STORAGE
12828 if (!str->used || str->str[str->used - 1] != '\r') {
12829 ast_str_append(&str, 0, "\r");
12830 }
12831 #endif
12832 ast_str_append(&str, 0, "\n");
12833 break;
12834 case 't':
12835 ast_str_append(&str, 0, "\t");
12836 break;
12837 default:
12838 ast_log(AST_LOG_NOTICE, "Substitution routine does not support this character: \\%c\n", *current);
12839 break;
12840 }
12841 } else {
12842 ast_str_append(&str, 0, "%c", *current);
12843 }
12844 }
12845
12846 return ast_str_buffer(str);
12847 }
12848
12849 static int load_config(int reload)
12850 {
12851 struct ast_config *cfg, *ucfg;
12852 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
12853 int res;
12854
12855 ast_unload_realtime("voicemail");
12856 ast_unload_realtime("voicemail_data");
12857
12858 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
12859 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
12860 return 0;
12861 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
12862 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
12863 ucfg = NULL;
12864 }
12865 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
12866 if ((cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
12867 ast_config_destroy(ucfg);
12868 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
12869 return 0;
12870 }
12871 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
12872 ast_log(LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
12873 return 0;
12874 } else {
12875 ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
12876 if ((ucfg = ast_config_load("users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
12877 ast_log(LOG_ERROR, "Config file users.conf is in an invalid format. Avoiding.\n");
12878 ucfg = NULL;
12879 }
12880 }
12881
12882 res = actual_load_config(reload, cfg, ucfg);
12883
12884 ast_config_destroy(cfg);
12885 ast_config_destroy(ucfg);
12886
12887 return res;
12888 }
12889
12890 #ifdef TEST_FRAMEWORK
12891 static int load_config_from_memory(int reload, struct ast_config *cfg, struct ast_config *ucfg)
12892 {
12893 ast_unload_realtime("voicemail");
12894 ast_unload_realtime("voicemail_data");
12895 return actual_load_config(reload, cfg, ucfg);
12896 }
12897 #endif
12898
12899 static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
12900 {
12901 struct ast_vm_user *current;
12902 char *cat;
12903 struct ast_variable *var;
12904 const char *val;
12905 char *q, *stringp, *tmp;
12906 int x;
12907 int tmpadsi[4];
12908 char secretfn[PATH_MAX] = "";
12909
12910 #ifdef IMAP_STORAGE
12911 ast_copy_string(imapparentfolder, "\0", sizeof(imapparentfolder));
12912 #endif
12913
12914 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
12915 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
12916 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
12917 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
12918 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
12919
12920
12921 free_vm_users();
12922
12923
12924 free_vm_zones();
12925
12926 AST_LIST_LOCK(&users);
12927
12928 memset(ext_pass_cmd, 0, sizeof(ext_pass_cmd));
12929 memset(ext_pass_check_cmd, 0, sizeof(ext_pass_check_cmd));
12930
12931 if (cfg) {
12932
12933
12934 if (!(val = ast_variable_retrieve(cfg, "general", "userscontext")))
12935 val = "default";
12936 ast_copy_string(userscontext, val, sizeof(userscontext));
12937
12938 if (!(val = ast_variable_retrieve(cfg, "general", "attach")))
12939 val = "yes";
12940 ast_set2_flag((&globalflags), ast_true(val), VM_ATTACH);
12941
12942 if (!(val = ast_variable_retrieve(cfg, "general", "searchcontexts")))
12943 val = "no";
12944 ast_set2_flag((&globalflags), ast_true(val), VM_SEARCH);
12945
12946 volgain = 0.0;
12947 if ((val = ast_variable_retrieve(cfg, "general", "volgain")))
12948 sscanf(val, "%30lf", &volgain);
12949
12950 #ifdef ODBC_STORAGE
12951 strcpy(odbc_database, "asterisk");
12952 if ((val = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
12953 ast_copy_string(odbc_database, val, sizeof(odbc_database));
12954 }
12955 strcpy(odbc_table, "voicemessages");
12956 if ((val = ast_variable_retrieve(cfg, "general", "odbctable"))) {
12957 ast_copy_string(odbc_table, val, sizeof(odbc_table));
12958 }
12959 #endif
12960
12961 strcpy(mailcmd, SENDMAIL);
12962 if ((val = ast_variable_retrieve(cfg, "general", "mailcmd")))
12963 ast_copy_string(mailcmd, val, sizeof(mailcmd));
12964
12965 maxsilence = 0;
12966 if ((val = ast_variable_retrieve(cfg, "general", "maxsilence"))) {
12967 maxsilence = atoi(val);
12968 if (maxsilence > 0)
12969 maxsilence *= 1000;
12970 }
12971
12972 if (!(val = ast_variable_retrieve(cfg, "general", "maxmsg"))) {
12973 maxmsg = MAXMSG;
12974 } else {
12975 maxmsg = atoi(val);
12976 if (maxmsg < 0) {
12977 ast_log(AST_LOG_WARNING, "Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
12978 maxmsg = MAXMSG;
12979 } else if (maxmsg > MAXMSGLIMIT) {
12980 ast_log(AST_LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
12981 maxmsg = MAXMSGLIMIT;
12982 }
12983 }
12984
12985 if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) {
12986 maxdeletedmsg = 0;
12987 } else {
12988 if (sscanf(val, "%30d", &x) == 1)
12989 maxdeletedmsg = x;
12990 else if (ast_true(val))
12991 maxdeletedmsg = MAXMSG;
12992 else
12993 maxdeletedmsg = 0;
12994
12995 if (maxdeletedmsg < 0) {
12996 ast_log(AST_LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
12997 maxdeletedmsg = MAXMSG;
12998 } else if (maxdeletedmsg > MAXMSGLIMIT) {
12999 ast_log(AST_LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
13000 maxdeletedmsg = MAXMSGLIMIT;
13001 }
13002 }
13003
13004
13005 if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) {
13006 ast_copy_string(emaildateformat, val, sizeof(emaildateformat));
13007 }
13008
13009
13010 if ((val = ast_variable_retrieve(cfg, "general", "pagerdateformat"))) {
13011 ast_copy_string(pagerdateformat, val, sizeof(pagerdateformat));
13012 }
13013
13014
13015 if ((val = ast_variable_retrieve(cfg, "general", "externpass"))) {
13016 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
13017 pwdchange = PWDCHANGE_EXTERNAL;
13018 } else if ((val = ast_variable_retrieve(cfg, "general", "externpassnotify"))) {
13019 ast_copy_string(ext_pass_cmd, val, sizeof(ext_pass_cmd));
13020 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
13021 }
13022
13023
13024 if ((val = ast_variable_retrieve(cfg, "general", "externpasscheck"))) {
13025 ast_copy_string(ext_pass_check_cmd, val, sizeof(ext_pass_check_cmd));
13026 ast_debug(1, "found externpasscheck: %s\n", ext_pass_check_cmd);
13027 }
13028
13029 #ifdef IMAP_STORAGE
13030
13031 if ((val = ast_variable_retrieve(cfg, "general", "imapserver"))) {
13032 ast_copy_string(imapserver, val, sizeof(imapserver));
13033 } else {
13034 ast_copy_string(imapserver, "localhost", sizeof(imapserver));
13035 }
13036
13037 if ((val = ast_variable_retrieve(cfg, "general", "imapport"))) {
13038 ast_copy_string(imapport, val, sizeof(imapport));
13039 } else {
13040 ast_copy_string(imapport, "143", sizeof(imapport));
13041 }
13042
13043 if ((val = ast_variable_retrieve(cfg, "general", "imapflags"))) {
13044 ast_copy_string(imapflags, val, sizeof(imapflags));
13045 }
13046
13047 if ((val = ast_variable_retrieve(cfg, "general", "authuser"))) {
13048 ast_copy_string(authuser, val, sizeof(authuser));
13049 }
13050
13051 if ((val = ast_variable_retrieve(cfg, "general", "authpassword"))) {
13052 ast_copy_string(authpassword, val, sizeof(authpassword));
13053 }
13054
13055 if ((val = ast_variable_retrieve(cfg, "general", "expungeonhangup"))) {
13056 if (ast_false(val))
13057 expungeonhangup = 0;
13058 else
13059 expungeonhangup = 1;
13060 } else {
13061 expungeonhangup = 1;
13062 }
13063
13064 if ((val = ast_variable_retrieve(cfg, "general", "imapfolder"))) {
13065 ast_copy_string(imapfolder, val, sizeof(imapfolder));
13066 } else {
13067 ast_copy_string(imapfolder, "INBOX", sizeof(imapfolder));
13068 }
13069 if ((val = ast_variable_retrieve(cfg, "general", "imapparentfolder"))) {
13070 ast_copy_string(imapparentfolder, val, sizeof(imapparentfolder));
13071 }
13072 if ((val = ast_variable_retrieve(cfg, "general", "imapgreetings"))) {
13073 imapgreetings = ast_true(val);
13074 } else {
13075 imapgreetings = 0;
13076 }
13077 if ((val = ast_variable_retrieve(cfg, "general", "greetingfolder"))) {
13078 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
13079 } else if ((val = ast_variable_retrieve(cfg, "general", "greetingsfolder"))) {
13080
13081 ast_copy_string(greetingfolder, val, sizeof(greetingfolder));
13082 } else {
13083 ast_copy_string(greetingfolder, imapfolder, sizeof(greetingfolder));
13084 }
13085
13086
13087
13088
13089
13090 if ((val = ast_variable_retrieve(cfg, "general", "imapreadtimeout"))) {
13091 mail_parameters(NIL, SET_READTIMEOUT, (void *) (atol(val)));
13092 } else {
13093 mail_parameters(NIL, SET_READTIMEOUT, (void *) 60L);
13094 }
13095
13096 if ((val = ast_variable_retrieve(cfg, "general", "imapwritetimeout"))) {
13097 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) (atol(val)));
13098 } else {
13099 mail_parameters(NIL, SET_WRITETIMEOUT, (void *) 60L);
13100 }
13101
13102 if ((val = ast_variable_retrieve(cfg, "general", "imapopentimeout"))) {
13103 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) (atol(val)));
13104 } else {
13105 mail_parameters(NIL, SET_OPENTIMEOUT, (void *) 60L);
13106 }
13107
13108 if ((val = ast_variable_retrieve(cfg, "general", "imapclosetimeout"))) {
13109 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) (atol(val)));
13110 } else {
13111 mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) 60L);
13112 }
13113
13114
13115 imapversion++;
13116 #endif
13117
13118 if ((val = ast_variable_retrieve(cfg, "general", "externnotify"))) {
13119 ast_copy_string(externnotify, val, sizeof(externnotify));
13120 ast_debug(1, "found externnotify: %s\n", externnotify);
13121 } else {
13122 externnotify[0] = '\0';
13123 }
13124
13125
13126 if ((val = ast_variable_retrieve(cfg, "general", "smdienable")) && ast_true(val)) {
13127 ast_debug(1, "Enabled SMDI voicemail notification\n");
13128 if ((val = ast_variable_retrieve(cfg, "general", "smdiport"))) {
13129 smdi_iface = ast_smdi_interface_find(val);
13130 } else {
13131 ast_debug(1, "No SMDI interface set, trying default (/dev/ttyS0)\n");
13132 smdi_iface = ast_smdi_interface_find("/dev/ttyS0");
13133 }
13134 if (!smdi_iface) {
13135 ast_log(AST_LOG_ERROR, "No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
13136 }
13137 }
13138
13139
13140 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
13141 if ((val = ast_variable_retrieve(cfg, "general", "silencethreshold")))
13142 silencethreshold = atoi(val);
13143
13144 if (!(val = ast_variable_retrieve(cfg, "general", "serveremail")))
13145 val = ASTERISK_USERNAME;
13146 ast_copy_string(serveremail, val, sizeof(serveremail));
13147
13148 vmmaxsecs = 0;
13149 if ((val = ast_variable_retrieve(cfg, "general", "maxsecs"))) {
13150 if (sscanf(val, "%30d", &x) == 1) {
13151 vmmaxsecs = x;
13152 } else {
13153 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
13154 }
13155 } else if ((val = ast_variable_retrieve(cfg, "general", "maxmessage"))) {
13156 static int maxmessage_deprecate = 0;
13157 if (maxmessage_deprecate == 0) {
13158 maxmessage_deprecate = 1;
13159 ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
13160 }
13161 if (sscanf(val, "%30d", &x) == 1) {
13162 vmmaxsecs = x;
13163 } else {
13164 ast_log(AST_LOG_WARNING, "Invalid max message time length\n");
13165 }
13166 }
13167
13168 vmminsecs = 0;
13169 if ((val = ast_variable_retrieve(cfg, "general", "minsecs"))) {
13170 if (sscanf(val, "%30d", &x) == 1) {
13171 vmminsecs = x;
13172 if (maxsilence / 1000 >= vmminsecs) {
13173 ast_log(AST_LOG_WARNING, "maxsilence should be less than minsecs or you may get empty messages\n");
13174 }
13175 } else {
13176 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
13177 }
13178 } else if ((val = ast_variable_retrieve(cfg, "general", "minmessage"))) {
13179 static int maxmessage_deprecate = 0;
13180 if (maxmessage_deprecate == 0) {
13181 maxmessage_deprecate = 1;
13182 ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
13183 }
13184 if (sscanf(val, "%30d", &x) == 1) {
13185 vmminsecs = x;
13186 if (maxsilence / 1000 >= vmminsecs) {
13187 ast_log(AST_LOG_WARNING, "maxsilence should be less than minmessage or you may get empty messages\n");
13188 }
13189 } else {
13190 ast_log(AST_LOG_WARNING, "Invalid min message time length\n");
13191 }
13192 }
13193
13194 val = ast_variable_retrieve(cfg, "general", "format");
13195 if (!val) {
13196 val = "wav";
13197 } else {
13198 tmp = ast_strdupa(val);
13199 val = ast_format_str_reduce(tmp);
13200 if (!val) {
13201 ast_log(LOG_ERROR, "Error processing format string, defaulting to format 'wav'\n");
13202 val = "wav";
13203 }
13204 }
13205 ast_copy_string(vmfmts, val, sizeof(vmfmts));
13206
13207 skipms = 3000;
13208 if ((val = ast_variable_retrieve(cfg, "general", "maxgreet"))) {
13209 if (sscanf(val, "%30d", &x) == 1) {
13210 maxgreet = x;
13211 } else {
13212 ast_log(AST_LOG_WARNING, "Invalid max message greeting length\n");
13213 }
13214 }
13215
13216 if ((val = ast_variable_retrieve(cfg, "general", "skipms"))) {
13217 if (sscanf(val, "%30d", &x) == 1) {
13218 skipms = x;
13219 } else {
13220 ast_log(AST_LOG_WARNING, "Invalid skipms value\n");
13221 }
13222 }
13223
13224 maxlogins = 3;
13225 if ((val = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
13226 if (sscanf(val, "%30d", &x) == 1) {
13227 maxlogins = x;
13228 } else {
13229 ast_log(AST_LOG_WARNING, "Invalid max failed login attempts\n");
13230 }
13231 }
13232
13233 minpassword = MINPASSWORD;
13234 if ((val = ast_variable_retrieve(cfg, "general", "minpassword"))) {
13235 if (sscanf(val, "%30d", &x) == 1) {
13236 minpassword = x;
13237 } else {
13238 ast_log(AST_LOG_WARNING, "Invalid minimum password length. Default to %d\n", minpassword);
13239 }
13240 }
13241
13242
13243 if (!(val = ast_variable_retrieve(cfg, "general", "forcename")))
13244 val = "no";
13245 ast_set2_flag((&globalflags), ast_true(val), VM_FORCENAME);
13246
13247
13248 if (!(val = ast_variable_retrieve(cfg, "general", "forcegreetings")))
13249 val = "no";
13250 ast_set2_flag((&globalflags), ast_true(val), VM_FORCEGREET);
13251
13252 if ((val = ast_variable_retrieve(cfg, "general", "cidinternalcontexts"))) {
13253 ast_debug(1, "VM_CID Internal context string: %s\n", val);
13254 stringp = ast_strdupa(val);
13255 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
13256 if (!ast_strlen_zero(stringp)) {
13257 q = strsep(&stringp, ",");
13258 while ((*q == ' ')||(*q == '\t'))
13259 q++;
13260 ast_copy_string(cidinternalcontexts[x], q, sizeof(cidinternalcontexts[x]));
13261 ast_debug(1, "VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
13262 } else {
13263 cidinternalcontexts[x][0] = '\0';
13264 }
13265 }
13266 }
13267 if (!(val = ast_variable_retrieve(cfg, "general", "review"))){
13268 ast_debug(1, "VM Review Option disabled globally\n");
13269 val = "no";
13270 }
13271 ast_set2_flag((&globalflags), ast_true(val), VM_REVIEW);
13272
13273
13274 if (!(val = ast_variable_retrieve(cfg, "general", "tempgreetwarn"))) {
13275 ast_debug(1, "VM Temporary Greeting Reminder Option disabled globally\n");
13276 val = "no";
13277 } else {
13278 ast_debug(1, "VM Temporary Greeting Reminder Option enabled globally\n");
13279 }
13280 ast_set2_flag((&globalflags), ast_true(val), VM_TEMPGREETWARN);
13281 if (!(val = ast_variable_retrieve(cfg, "general", "messagewrap"))){
13282 ast_debug(1, "VM next message wrap disabled globally\n");
13283 val = "no";
13284 }
13285 ast_set2_flag((&globalflags), ast_true(val), VM_MESSAGEWRAP);
13286
13287 if (!(val = ast_variable_retrieve(cfg, "general", "operator"))){
13288 ast_debug(1, "VM Operator break disabled globally\n");
13289 val = "no";
13290 }
13291 ast_set2_flag((&globalflags), ast_true(val), VM_OPERATOR);
13292
13293 if (!(val = ast_variable_retrieve(cfg, "general", "saycid"))) {
13294 ast_debug(1, "VM CID Info before msg disabled globally\n");
13295 val = "no";
13296 }
13297 ast_set2_flag((&globalflags), ast_true(val), VM_SAYCID);
13298
13299 if (!(val = ast_variable_retrieve(cfg, "general", "sendvoicemail"))){
13300 ast_debug(1, "Send Voicemail msg disabled globally\n");
13301 val = "no";
13302 }
13303 ast_set2_flag((&globalflags), ast_true(val), VM_SVMAIL);
13304
13305 if (!(val = ast_variable_retrieve(cfg, "general", "envelope"))) {
13306 ast_debug(1, "ENVELOPE before msg enabled globally\n");
13307 val = "yes";
13308 }
13309 ast_set2_flag((&globalflags), ast_true(val), VM_ENVELOPE);
13310
13311 if (!(val = ast_variable_retrieve(cfg, "general", "moveheard"))) {
13312 ast_debug(1, "Move Heard enabled globally\n");
13313 val = "yes";
13314 }
13315 ast_set2_flag((&globalflags), ast_true(val), VM_MOVEHEARD);
13316
13317 if (!(val = ast_variable_retrieve(cfg, "general", "forward_urgent_auto"))) {
13318 ast_debug(1, "Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
13319 val = "no";
13320 }
13321 ast_set2_flag((&globalflags), ast_true(val), VM_FWDURGAUTO);
13322
13323 if (!(val = ast_variable_retrieve(cfg, "general", "sayduration"))) {
13324 ast_debug(1, "Duration info before msg enabled globally\n");
13325 val = "yes";
13326 }
13327 ast_set2_flag((&globalflags), ast_true(val), VM_SAYDURATION);
13328
13329 saydurationminfo = 2;
13330 if ((val = ast_variable_retrieve(cfg, "general", "saydurationm"))) {
13331 if (sscanf(val, "%30d", &x) == 1) {
13332 saydurationminfo = x;
13333 } else {
13334 ast_log(AST_LOG_WARNING, "Invalid min duration for say duration\n");
13335 }
13336 }
13337
13338 if (!(val = ast_variable_retrieve(cfg, "general", "nextaftercmd"))) {
13339 ast_debug(1, "We are not going to skip to the next msg after save/delete\n");
13340 val = "no";
13341 }
13342 ast_set2_flag((&globalflags), ast_true(val), VM_SKIPAFTERCMD);
13343
13344 if ((val = ast_variable_retrieve(cfg, "general", "dialout"))) {
13345 ast_copy_string(dialcontext, val, sizeof(dialcontext));
13346 ast_debug(1, "found dialout context: %s\n", dialcontext);
13347 } else {
13348 dialcontext[0] = '\0';
13349 }
13350
13351 if ((val = ast_variable_retrieve(cfg, "general", "callback"))) {
13352 ast_copy_string(callcontext, val, sizeof(callcontext));
13353 ast_debug(1, "found callback context: %s\n", callcontext);
13354 } else {
13355 callcontext[0] = '\0';
13356 }
13357
13358 if ((val = ast_variable_retrieve(cfg, "general", "exitcontext"))) {
13359 ast_copy_string(exitcontext, val, sizeof(exitcontext));
13360 ast_debug(1, "found operator context: %s\n", exitcontext);
13361 } else {
13362 exitcontext[0] = '\0';
13363 }
13364
13365
13366 if ((val = ast_variable_retrieve(cfg, "general", "vm-password")))
13367 ast_copy_string(vm_password, val, sizeof(vm_password));
13368 if ((val = ast_variable_retrieve(cfg, "general", "vm-newpassword")))
13369 ast_copy_string(vm_newpassword, val, sizeof(vm_newpassword));
13370 if ((val = ast_variable_retrieve(cfg, "general", "vm-invalid-password")))
13371 ast_copy_string(vm_invalid_password, val, sizeof(vm_invalid_password));
13372 if ((val = ast_variable_retrieve(cfg, "general", "vm-passchanged")))
13373 ast_copy_string(vm_passchanged, val, sizeof(vm_passchanged));
13374 if ((val = ast_variable_retrieve(cfg, "general", "vm-reenterpassword")))
13375 ast_copy_string(vm_reenterpassword, val, sizeof(vm_reenterpassword));
13376 if ((val = ast_variable_retrieve(cfg, "general", "vm-mismatch")))
13377 ast_copy_string(vm_mismatch, val, sizeof(vm_mismatch));
13378 if ((val = ast_variable_retrieve(cfg, "general", "vm-pls-try-again"))) {
13379 ast_copy_string(vm_pls_try_again, val, sizeof(vm_pls_try_again));
13380 }
13381 if ((val = ast_variable_retrieve(cfg, "general", "vm-prepend-timeout"))) {
13382 ast_copy_string(vm_prepend_timeout, val, sizeof(vm_prepend_timeout));
13383 }
13384
13385 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-forward-key")) && is_valid_dtmf(val))
13386 ast_copy_string(listen_control_forward_key, val, sizeof(listen_control_forward_key));
13387 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-reverse-key")) && is_valid_dtmf(val))
13388 ast_copy_string(listen_control_reverse_key, val, sizeof(listen_control_reverse_key));
13389 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-pause-key")) && is_valid_dtmf(val))
13390 ast_copy_string(listen_control_pause_key, val, sizeof(listen_control_pause_key));
13391 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-restart-key")) && is_valid_dtmf(val))
13392 ast_copy_string(listen_control_restart_key, val, sizeof(listen_control_restart_key));
13393 if ((val = ast_variable_retrieve(cfg, "general", "listen-control-stop-key")) && is_valid_dtmf(val))
13394 ast_copy_string(listen_control_stop_key, val, sizeof(listen_control_stop_key));
13395
13396 if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory")))
13397 val = "no";
13398 ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);
13399
13400 if (!(val = ast_variable_retrieve(cfg, "general", "passwordlocation"))) {
13401 val = "voicemail.conf";
13402 }
13403 if (!(strcmp(val, "spooldir"))) {
13404 passwordlocation = OPT_PWLOC_SPOOLDIR;
13405 } else {
13406 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
13407 }
13408
13409 poll_freq = DEFAULT_POLL_FREQ;
13410 if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
13411 if (sscanf(val, "%30u", &poll_freq) != 1) {
13412 poll_freq = DEFAULT_POLL_FREQ;
13413 ast_log(AST_LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
13414 }
13415 }
13416
13417 poll_mailboxes = 0;
13418 if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
13419 poll_mailboxes = ast_true(val);
13420
13421 memset(fromstring, 0, sizeof(fromstring));
13422 memset(pagerfromstring, 0, sizeof(pagerfromstring));
13423 strcpy(charset, "ISO-8859-1");
13424 if (emailbody) {
13425 ast_free(emailbody);
13426 emailbody = NULL;
13427 }
13428 if (emailsubject) {
13429 ast_free(emailsubject);
13430 emailsubject = NULL;
13431 }
13432 if (pagerbody) {
13433 ast_free(pagerbody);
13434 pagerbody = NULL;
13435 }
13436 if (pagersubject) {
13437 ast_free(pagersubject);
13438 pagersubject = NULL;
13439 }
13440 if ((val = ast_variable_retrieve(cfg, "general", "pbxskip")))
13441 ast_set2_flag((&globalflags), ast_true(val), VM_PBXSKIP);
13442 if ((val = ast_variable_retrieve(cfg, "general", "fromstring")))
13443 ast_copy_string(fromstring, val, sizeof(fromstring));
13444 if ((val = ast_variable_retrieve(cfg, "general", "pagerfromstring")))
13445 ast_copy_string(pagerfromstring, val, sizeof(pagerfromstring));
13446 if ((val = ast_variable_retrieve(cfg, "general", "charset")))
13447 ast_copy_string(charset, val, sizeof(charset));
13448 if ((val = ast_variable_retrieve(cfg, "general", "adsifdn"))) {
13449 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
13450 for (x = 0; x < 4; x++) {
13451 memcpy(&adsifdn[x], &tmpadsi[x], 1);
13452 }
13453 }
13454 if ((val = ast_variable_retrieve(cfg, "general", "adsisec"))) {
13455 sscanf(val, "%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
13456 for (x = 0; x < 4; x++) {
13457 memcpy(&adsisec[x], &tmpadsi[x], 1);
13458 }
13459 }
13460 if ((val = ast_variable_retrieve(cfg, "general", "adsiver"))) {
13461 if (atoi(val)) {
13462 adsiver = atoi(val);
13463 }
13464 }
13465 if ((val = ast_variable_retrieve(cfg, "general", "tz"))) {
13466 ast_copy_string(zonetag, val, sizeof(zonetag));
13467 }
13468 if ((val = ast_variable_retrieve(cfg, "general", "locale"))) {
13469 ast_copy_string(locale, val, sizeof(locale));
13470 }
13471 if ((val = ast_variable_retrieve(cfg, "general", "emailsubject"))) {
13472 emailsubject = ast_strdup(substitute_escapes(val));
13473 }
13474 if ((val = ast_variable_retrieve(cfg, "general", "emailbody"))) {
13475 emailbody = ast_strdup(substitute_escapes(val));
13476 }
13477 if ((val = ast_variable_retrieve(cfg, "general", "pagersubject"))) {
13478 pagersubject = ast_strdup(substitute_escapes(val));
13479 }
13480 if ((val = ast_variable_retrieve(cfg, "general", "pagerbody"))) {
13481 pagerbody = ast_strdup(substitute_escapes(val));
13482 }
13483
13484
13485 if (ucfg) {
13486 for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
13487 if (!strcasecmp(cat, "general")) {
13488 continue;
13489 }
13490 if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
13491 continue;
13492 if ((current = find_or_create(userscontext, cat))) {
13493 populate_defaults(current);
13494 apply_options_full(current, ast_variable_browse(ucfg, cat));
13495 ast_copy_string(current->context, userscontext, sizeof(current->context));
13496 if (!ast_strlen_zero(current->password) && current->passwordlocation == OPT_PWLOC_VOICEMAILCONF) {
13497 current->passwordlocation = OPT_PWLOC_USERSCONF;
13498 }
13499
13500 switch (current->passwordlocation) {
13501 case OPT_PWLOC_SPOOLDIR:
13502 snprintf(secretfn, sizeof(secretfn), "%s%s/%s/secret.conf", VM_SPOOL_DIR, current->context, current->mailbox);
13503 read_password_from_file(secretfn, current->password, sizeof(current->password));
13504 }
13505 }
13506 }
13507 }
13508
13509
13510 cat = ast_category_browse(cfg, NULL);
13511 while (cat) {
13512 if (strcasecmp(cat, "general")) {
13513 var = ast_variable_browse(cfg, cat);
13514 if (strcasecmp(cat, "zonemessages")) {
13515
13516 while (var) {
13517 append_mailbox(cat, var->name, var->value);
13518 var = var->next;
13519 }
13520 } else {
13521
13522 while (var) {
13523 struct vm_zone *z;
13524 if ((z = ast_malloc(sizeof(*z)))) {
13525 char *msg_format, *tzone;
13526 msg_format = ast_strdupa(var->value);
13527 tzone = strsep(&msg_format, "|,");
13528 if (msg_format) {
13529 ast_copy_string(z->name, var->name, sizeof(z->name));
13530 ast_copy_string(z->timezone, tzone, sizeof(z->timezone));
13531 ast_copy_string(z->msg_format, msg_format, sizeof(z->msg_format));
13532 AST_LIST_LOCK(&zones);
13533 AST_LIST_INSERT_HEAD(&zones, z, list);
13534 AST_LIST_UNLOCK(&zones);
13535 } else {
13536 ast_log(AST_LOG_WARNING, "Invalid timezone definition at line %d\n", var->lineno);
13537 ast_free(z);
13538 }
13539 } else {
13540 AST_LIST_UNLOCK(&users);
13541 return -1;
13542 }
13543 var = var->next;
13544 }
13545 }
13546 }
13547 cat = ast_category_browse(cfg, cat);
13548 }
13549
13550 AST_LIST_UNLOCK(&users);
13551
13552 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
13553 start_poll_thread();
13554 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
13555 stop_poll_thread();;
13556
13557 return 0;
13558 } else {
13559 AST_LIST_UNLOCK(&users);
13560 ast_log(AST_LOG_WARNING, "Failed to load configuration file.\n");
13561 return 0;
13562 }
13563 }
13564
13565 static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
13566 {
13567 int res = -1;
13568 char dir[PATH_MAX];
13569 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
13570 ast_debug(2, "About to try retrieving name file %s\n", dir);
13571 RETRIEVE(dir, -1, mailbox, context);
13572 if (ast_fileexists(dir, NULL, NULL)) {
13573 res = ast_stream_and_wait(chan, dir, AST_DIGIT_ANY);
13574 }
13575 DISPOSE(dir, -1);
13576 return res;
13577 }
13578
13579 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
13580 struct ast_config *pwconf;
13581 struct ast_flags config_flags = { 0 };
13582
13583 pwconf = ast_config_load(secretfn, config_flags);
13584 if (valid_config(pwconf)) {
13585 const char *val = ast_variable_retrieve(pwconf, "general", "password");
13586 if (val) {
13587 ast_copy_string(password, val, passwordlen);
13588 ast_config_destroy(pwconf);
13589 return;
13590 }
13591 ast_config_destroy(pwconf);
13592 }
13593 ast_log(LOG_NOTICE, "Failed reading voicemail password from %s, using secret from config file\n", secretfn);
13594 }
13595
13596 static int write_password_to_file(const char *secretfn, const char *password) {
13597 struct ast_config *conf;
13598 struct ast_category *cat;
13599 struct ast_variable *var;
13600 int res = -1;
13601
13602 if (!(conf = ast_config_new())) {
13603 ast_log(LOG_ERROR, "Error creating new config structure\n");
13604 return res;
13605 }
13606 if (!(cat = ast_category_new("general", "", 1))) {
13607 ast_log(LOG_ERROR, "Error creating new category structure\n");
13608 ast_config_destroy(conf);
13609 return res;
13610 }
13611 if (!(var = ast_variable_new("password", password, ""))) {
13612 ast_log(LOG_ERROR, "Error creating new variable structure\n");
13613 ast_config_destroy(conf);
13614 ast_category_destroy(cat);
13615 return res;
13616 }
13617 ast_category_append(conf, cat);
13618 ast_variable_append(cat, var);
13619 if (!ast_config_text_file_save(secretfn, conf, "app_voicemail")) {
13620 res = 0;
13621 } else {
13622 ast_log(LOG_ERROR, "Error writing voicemail password to %s\n", secretfn);
13623 }
13624
13625 ast_config_destroy(conf);
13626 return res;
13627 }
13628
13629 static int vmsayname_exec(struct ast_channel *chan, const char *data)
13630 {
13631 char *context;
13632 char *args_copy;
13633 int res;
13634
13635 if (ast_strlen_zero(data)) {
13636 ast_log(LOG_WARNING, "VMSayName requires argument mailbox@context\n");
13637 return -1;
13638 }
13639
13640 args_copy = ast_strdupa(data);
13641 if ((context = strchr(args_copy, '@'))) {
13642 *context++ = '\0';
13643 } else {
13644 context = "default";
13645 }
13646
13647 if ((res = sayname(chan, args_copy, context)) < 0) {
13648 ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
13649 res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY);
13650 if (!res) {
13651 res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, ast_channel_language(chan));
13652 }
13653 }
13654
13655 return res;
13656 }
13657
13658 #ifdef TEST_FRAMEWORK
13659 static int fake_write(struct ast_channel *ast, struct ast_frame *frame)
13660 {
13661 return 0;
13662 }
13663
13664 static struct ast_frame *fake_read(struct ast_channel *ast)
13665 {
13666 return &ast_null_frame;
13667 }
13668
13669 AST_TEST_DEFINE(test_voicemail_vmsayname)
13670 {
13671 char dir[PATH_MAX];
13672 char dir2[PATH_MAX];
13673 static const char TEST_CONTEXT[] = "very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
13674 static const char TEST_EXTENSION[] = "1234";
13675
13676 struct ast_channel *test_channel1 = NULL;
13677 int res = -1;
13678 struct ast_format_cap *nativeformats;
13679
13680 static const struct ast_channel_tech fake_tech = {
13681 .write = fake_write,
13682 .read = fake_read,
13683 };
13684
13685 switch (cmd) {
13686 case TEST_INIT:
13687 info->name = "vmsayname_exec";
13688 info->category = "/apps/app_voicemail/";
13689 info->summary = "Vmsayname unit test";
13690 info->description =
13691 "This tests passing various parameters to vmsayname";
13692 return AST_TEST_NOT_RUN;
13693 case TEST_EXECUTE:
13694 break;
13695 }
13696
13697 if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
13698 NULL, NULL, 0, 0, "TestChannel1"))) {
13699 goto exit_vmsayname_test;
13700 }
13701
13702
13703 ast_format_set(ast_channel_writeformat(test_channel1), AST_FORMAT_GSM, 0);
13704 nativeformats = ast_channel_nativeformats(test_channel1);
13705 ast_format_cap_add(nativeformats, ast_channel_writeformat(test_channel1));
13706 ast_format_set(ast_channel_rawwriteformat(test_channel1), AST_FORMAT_GSM, 0);
13707 ast_format_set(ast_channel_readformat(test_channel1), AST_FORMAT_GSM, 0);
13708 ast_format_set(ast_channel_rawreadformat(test_channel1), AST_FORMAT_GSM, 0);
13709 ast_channel_tech_set(test_channel1, &fake_tech);
13710
13711 ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
13712 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
13713 if (!(res = vmsayname_exec(test_channel1, dir))) {
13714 snprintf(dir, sizeof(dir), "%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
13715 if (ast_fileexists(dir, NULL, NULL)) {
13716 ast_test_status_update(test, "This should not happen, most likely means clean up from previous test failed\n");
13717 res = -1;
13718 goto exit_vmsayname_test;
13719 } else {
13720
13721 if ((res = create_dirpath(dir, sizeof(dir), TEST_CONTEXT, TEST_EXTENSION, ""))) {
13722 ast_log(AST_LOG_WARNING, "Failed to make test directory\n");
13723 goto exit_vmsayname_test;
13724 }
13725 snprintf(dir, sizeof(dir), "%s/sounds/beep.gsm", ast_config_AST_VAR_DIR);
13726 snprintf(dir2, sizeof(dir2), "%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
13727
13728 if ((res = symlink(dir, dir2))) {
13729 ast_log(LOG_WARNING, "Symlink reported %s\n", strerror(errno));
13730 goto exit_vmsayname_test;
13731 }
13732 ast_test_status_update(test, "Test playing created mailbox greeting...\n");
13733 snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT);
13734 res = vmsayname_exec(test_channel1, dir);
13735
13736
13737 unlink(dir2);
13738 snprintf(dir2, sizeof(dir2), "%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
13739 rmdir(dir2);
13740 snprintf(dir2, sizeof(dir2), "%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
13741 rmdir(dir2);
13742 }
13743 }
13744
13745 exit_vmsayname_test:
13746
13747 if (test_channel1) {
13748 ast_hangup(test_channel1);
13749 }
13750
13751 return res ? AST_TEST_FAIL : AST_TEST_PASS;
13752 }
13753
13754 AST_TEST_DEFINE(test_voicemail_msgcount)
13755 {
13756 int i, j, res = AST_TEST_PASS, syserr;
13757 struct ast_vm_user *vmu;
13758 struct ast_vm_user svm;
13759 struct vm_state vms;
13760 #ifdef IMAP_STORAGE
13761 struct ast_channel *chan = NULL;
13762 #endif
13763 struct {
13764 char dir[256];
13765 char file[256];
13766 char txtfile[256];
13767 } tmp[3];
13768 char syscmd[256];
13769 const char origweasels[] = "tt-weasels";
13770 const char testcontext[] = "test";
13771 const char testmailbox[] = "00000000";
13772 const char testspec[] = "00000000@test";
13773 FILE *txt;
13774 int new, old, urgent;
13775 const char *folders[3] = { "Old", "Urgent", "INBOX" };
13776 const int folder2mbox[3] = { 1, 11, 0 };
13777 const int expected_results[3][12] = {
13778
13779 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
13780 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
13781 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
13782 };
13783
13784 switch (cmd) {
13785 case TEST_INIT:
13786 info->name = "test_voicemail_msgcount";
13787 info->category = "/apps/app_voicemail/";
13788 info->summary = "Test Voicemail status checks";
13789 info->description =
13790 "Verify that message counts are correct when retrieved through the public API";
13791 return AST_TEST_NOT_RUN;
13792 case TEST_EXECUTE:
13793 break;
13794 }
13795
13796
13797 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
13798 if ((syserr = ast_safe_system(syscmd))) {
13799 ast_test_status_update(test, "Unable to clear test directory: %s\n",
13800 syserr > 0 ? strerror(syserr) : "unable to fork()");
13801 return AST_TEST_FAIL;
13802 }
13803
13804 #ifdef IMAP_STORAGE
13805 if (!(chan = ast_dummy_channel_alloc())) {
13806 ast_test_status_update(test, "Unable to create dummy channel\n");
13807 return AST_TEST_FAIL;
13808 }
13809 #endif
13810
13811 if (!(vmu = find_user(&svm, testcontext, testmailbox)) &&
13812 !(vmu = find_or_create(testcontext, testmailbox))) {
13813 ast_test_status_update(test, "Cannot create vmu structure\n");
13814 ast_unreplace_sigchld();
13815 #ifdef IMAP_STORAGE
13816 chan = ast_channel_unref(chan);
13817 #endif
13818 return AST_TEST_FAIL;
13819 }
13820
13821 populate_defaults(vmu);
13822 memset(&vms, 0, sizeof(vms));
13823
13824
13825 for (i = 0; i < 3; i++) {
13826 create_dirpath(tmp[i].dir, sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
13827 make_file(tmp[i].file, sizeof(tmp[i].file), tmp[i].dir, 0);
13828 snprintf(tmp[i].txtfile, sizeof(tmp[i].txtfile), "%s.txt", tmp[i].file);
13829
13830 if (ast_fileexists(origweasels, "gsm", "en") > 0) {
13831 snprintf(syscmd, sizeof(syscmd), "cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
13832 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
13833 if ((syserr = ast_safe_system(syscmd))) {
13834 ast_test_status_update(test, "Unable to create test voicemail: %s\n",
13835 syserr > 0 ? strerror(syserr) : "unable to fork()");
13836 ast_unreplace_sigchld();
13837 #ifdef IMAP_STORAGE
13838 chan = ast_channel_unref(chan);
13839 #endif
13840 return AST_TEST_FAIL;
13841 }
13842 }
13843
13844 if ((txt = fopen(tmp[i].txtfile, "w+"))) {
13845 fprintf(txt, "; just a stub\n[message]\nflag=%s\n", strcmp(folders[i], "Urgent") ? "" : "Urgent");
13846 fclose(txt);
13847 } else {
13848 ast_test_status_update(test, "Unable to write message file '%s'\n", tmp[i].txtfile);
13849 res = AST_TEST_FAIL;
13850 break;
13851 }
13852 open_mailbox(&vms, vmu, folder2mbox[i]);
13853 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu, "gsm", 600, &vms, strcmp(folders[i], "Urgent") ? "" : "Urgent", NULL);
13854
13855
13856 for (j = 0; j < 3; j++) {
13857
13858 if (ast_app_has_voicemail(testspec, (j==2 ? NULL : folders[j])) != expected_results[i][0 + j]) {
13859 ast_test_status_update(test, "has_voicemail(%s, %s) returned %d and we expected %d\n",
13860 testspec, folders[j], ast_app_has_voicemail(testspec, folders[j]), expected_results[i][0 + j]);
13861 res = AST_TEST_FAIL;
13862 }
13863 }
13864
13865 new = old = urgent = 0;
13866 if (ast_app_inboxcount(testspec, &new, &old)) {
13867 ast_test_status_update(test, "inboxcount returned failure\n");
13868 res = AST_TEST_FAIL;
13869 } else if (old != expected_results[i][3 + 0] || new != expected_results[i][3 + 2]) {
13870 ast_test_status_update(test, "inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
13871 testspec, old, expected_results[i][3 + 0], new, expected_results[i][3 + 2]);
13872 res = AST_TEST_FAIL;
13873 }
13874
13875 new = old = urgent = 0;
13876 if (ast_app_inboxcount2(testspec, &urgent, &new, &old)) {
13877 ast_test_status_update(test, "inboxcount2 returned failure\n");
13878 res = AST_TEST_FAIL;
13879 } else if (old != expected_results[i][6 + 0] ||
13880 urgent != expected_results[i][6 + 1] ||
13881 new != expected_results[i][6 + 2] ) {
13882 ast_test_status_update(test, "inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
13883 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1], new, expected_results[i][6 + 2]);
13884 res = AST_TEST_FAIL;
13885 }
13886
13887 new = old = urgent = 0;
13888 for (j = 0; j < 3; j++) {
13889 if (ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
13890 ast_test_status_update(test, "messagecount(%s, %s) returned %d and we expected %d\n",
13891 testspec, folders[j], ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
13892 res = AST_TEST_FAIL;
13893 }
13894 }
13895 }
13896
13897 for (i = 0; i < 3; i++) {
13898
13899
13900
13901 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
13902 DISPOSE(tmp[i].dir, 0);
13903 }
13904
13905 if (vms.deleted) {
13906 ast_free(vms.deleted);
13907 }
13908 if (vms.heard) {
13909 ast_free(vms.heard);
13910 }
13911
13912 #ifdef IMAP_STORAGE
13913 chan = ast_channel_unref(chan);
13914 #endif
13915
13916
13917 snprintf(syscmd, sizeof(syscmd), "rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
13918 if ((syserr = ast_safe_system(syscmd))) {
13919 ast_test_status_update(test, "Unable to clear test directory: %s\n",
13920 syserr > 0 ? strerror(syserr) : "unable to fork()");
13921 }
13922
13923 return res;
13924 }
13925
13926 AST_TEST_DEFINE(test_voicemail_notify_endl)
13927 {
13928 int res = AST_TEST_PASS;
13929 char testcontext[] = "test";
13930 char testmailbox[] = "00000000";
13931 char from[] = "test@example.net", cidnum[] = "1234", cidname[] = "Mark Spencer", format[] = "gsm";
13932 char attach[256], attach2[256];
13933 char buf[256] = "";
13934 struct ast_channel *chan = NULL;
13935 struct ast_vm_user *vmu, vmus = {
13936 .flags = 0,
13937 };
13938 FILE *file;
13939 struct {
13940 char *name;
13941 enum { INT, FLAGVAL, STATIC, STRPTR } type;
13942 void *location;
13943 union {
13944 int intval;
13945 char *strval;
13946 } u;
13947 } test_items[] = {
13948 { "plain jane config", STATIC, vmus.password, .u.strval = "1234" },
13949 { "emailsubject", STRPTR, vmus.emailsubject, .u.strval = "Oogly boogly\xf8koogly with what appears to be UTF-8" },
13950 { "emailbody", STRPTR, vmus.emailbody, .u.strval = "This is a test\n\twith multiple\nlines\nwithin\n" },
13951 { "serveremail", STATIC, vmus.serveremail, .u.strval = "\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
13952 { "attachment flag", FLAGVAL, &vmus.flags, .u.intval = VM_ATTACH },
13953 { "attach2", STRPTR, attach2, .u.strval = "" },
13954 { "attach", STRPTR, attach, .u.strval = "" },
13955 };
13956 int which;
13957
13958 switch (cmd) {
13959 case TEST_INIT:
13960 info->name = "test_voicemail_notify_endl";
13961 info->category = "/apps/app_voicemail/";
13962 info->summary = "Test Voicemail notification end-of-line";
13963 info->description =
13964 "Verify that notification emails use a consistent end-of-line character";
13965 return AST_TEST_NOT_RUN;
13966 case TEST_EXECUTE:
13967 break;
13968 }
13969
13970 snprintf(attach, sizeof(attach), "%s/sounds/en/tt-weasels", ast_config_AST_VAR_DIR);
13971 snprintf(attach2, sizeof(attach2), "%s/sounds/en/tt-somethingwrong", ast_config_AST_VAR_DIR);
13972
13973 if (!(vmu = find_user(&vmus, testcontext, testmailbox)) &&
13974 !(vmu = find_or_create(testcontext, testmailbox))) {
13975 ast_test_status_update(test, "Cannot create vmu structure\n");
13976 return AST_TEST_NOT_RUN;
13977 }
13978
13979 if (vmu != &vmus && !(vmu = find_user(&vmus, testcontext, testmailbox))) {
13980 ast_test_status_update(test, "Cannot find vmu structure?!!\n");
13981 return AST_TEST_NOT_RUN;
13982 }
13983
13984 populate_defaults(vmu);
13985 ast_copy_string(vmu->email, "test2@example.net", sizeof(vmu->email));
13986 #ifdef IMAP_STORAGE
13987
13988 #endif
13989
13990 file = tmpfile();
13991 for (which = 0; which < ARRAY_LEN(test_items); which++) {
13992
13993 rewind(file);
13994 if (ftruncate(fileno(file), 0)) {
13995 ast_test_status_update(test, "Cannot truncate test output file: %s\n", strerror(errno));
13996 res = AST_TEST_FAIL;
13997 break;
13998 }
13999
14000
14001 if (test_items[which].type == INT) {
14002 *((int *) test_items[which].location) = test_items[which].u.intval;
14003 } else if (test_items[which].type == FLAGVAL) {
14004 if (ast_test_flag(vmu, test_items[which].u.intval)) {
14005 ast_clear_flag(vmu, test_items[which].u.intval);
14006 } else {
14007 ast_set_flag(vmu, test_items[which].u.intval);
14008 }
14009 } else if (test_items[which].type == STATIC) {
14010 strcpy(test_items[which].location, test_items[which].u.strval);
14011 } else if (test_items[which].type == STRPTR) {
14012 test_items[which].location = test_items[which].u.strval;
14013 }
14014
14015 make_email_file(file, from, vmu, 0, testcontext, testmailbox, "INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL, NULL);
14016 rewind(file);
14017 while (fgets(buf, sizeof(buf), file)) {
14018 if (
14019 #ifdef IMAP_STORAGE
14020 buf[strlen(buf) - 2] != '\r'
14021 #else
14022 buf[strlen(buf) - 2] == '\r'
14023 #endif
14024 || buf[strlen(buf) - 1] != '\n') {
14025 res = AST_TEST_FAIL;
14026 }
14027 }
14028 }
14029 fclose(file);
14030 return res;
14031 }
14032
14033 AST_TEST_DEFINE(test_voicemail_load_config)
14034 {
14035 int res = AST_TEST_PASS;
14036 struct ast_vm_user *vmu;
14037 struct ast_config *cfg;
14038 char config_filename[32] = "/tmp/voicemail.conf.XXXXXX";
14039 int fd;
14040 FILE *file;
14041 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
14042
14043 switch (cmd) {
14044 case TEST_INIT:
14045 info->name = "test_voicemail_load_config";
14046 info->category = "/apps/app_voicemail/";
14047 info->summary = "Test loading Voicemail config";
14048 info->description =
14049 "Verify that configuration is loaded consistently. "
14050 "This is to test regressions of ASTERISK-18838 where it was noticed that "
14051 "some options were loaded after the mailboxes were instantiated, causing "
14052 "those options not to be set correctly.";
14053 return AST_TEST_NOT_RUN;
14054 case TEST_EXECUTE:
14055 break;
14056 }
14057
14058
14059 if ((fd = mkstemp(config_filename)) < 0) {
14060 return AST_TEST_FAIL;
14061 }
14062 if (!(file = fdopen(fd, "w"))) {
14063 close(fd);
14064 unlink(config_filename);
14065 return AST_TEST_FAIL;
14066 }
14067 fputs("[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
14068 fputs("00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
14069 fputs("00000002 => 9999,Mrs. Test\n", file);
14070 fclose(file);
14071
14072 if (!(cfg = ast_config_load(config_filename, config_flags)) || !valid_config(cfg)) {
14073 res = AST_TEST_FAIL;
14074 goto cleanup;
14075 }
14076
14077 load_config_from_memory(1, cfg, NULL);
14078 ast_config_destroy(cfg);
14079
14080 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
14081 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
14082 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
14083
14084 AST_LIST_LOCK(&users);
14085 AST_LIST_TRAVERSE(&users, vmu, list) {
14086 if (!strcmp(vmu->mailbox, "00000001")) {
14087 if (0);
14088 CHECK(vmu, callback, "othercontext")
14089 CHECK(vmu, locale, "nl_NL.UTF-8")
14090 CHECK(vmu, zonetag, "central")
14091 } else if (!strcmp(vmu->mailbox, "00000002")) {
14092 if (0);
14093 CHECK(vmu, callback, "somecontext")
14094 CHECK(vmu, locale, "de_DE.UTF-8")
14095 CHECK(vmu, zonetag, "european")
14096 }
14097 }
14098 AST_LIST_UNLOCK(&users);
14099
14100 #undef CHECK
14101
14102
14103 load_config(1);
14104
14105 cleanup:
14106 unlink(config_filename);
14107 return res;
14108 }
14109
14110 AST_TEST_DEFINE(test_voicemail_vm_info)
14111 {
14112 struct ast_vm_user *vmu;
14113 struct ast_channel *chan = NULL;
14114 const char testcontext[] = "test";
14115 const char testmailbox[] = "00000000";
14116 const char vminfo_cmd[] = "VM_INFO";
14117 char vminfo_buf[256], vminfo_args[256];
14118 int res = AST_TEST_PASS;
14119 int test_ret = 0;
14120 int test_counter = 0;
14121
14122 struct {
14123 char *vminfo_test_args;
14124 char *vminfo_expected;
14125 int vminfo_ret;
14126 } test_items[] = {
14127 { "", "", -1 },
14128 { "00000000@test,badparam", "", -1 },
14129 { "00000000@test", "", -1 },
14130 { "00000000@test,exists", "1", 0 },
14131 { "11111111@test,exists", "0", 0 },
14132 { "00000000@test,email", "vm-info-test@example.net", 0 },
14133 { "11111111@test,email", "", 0 },
14134 { "00000000@test,fullname", "Test Framework Mailbox", 0 },
14135 { "00000000@test,pager", "vm-info-pager-test@example.net", 0 },
14136 { "00000000@test,locale", "en_US", 0 },
14137 { "00000000@test,tz", "central", 0 },
14138 { "00000000@test,language", "en", 0 },
14139 { "00000000@test,password", "9876", 0 },
14140 };
14141
14142 switch (cmd) {
14143 case TEST_INIT:
14144 info->name = "test_voicemail_vm_info";
14145 info->category = "/apps/app_voicemail/";
14146 info->summary = "VM_INFO unit test";
14147 info->description =
14148 "This tests passing various parameters to VM_INFO";
14149 return AST_TEST_NOT_RUN;
14150 case TEST_EXECUTE:
14151 break;
14152 }
14153
14154 if (!(chan = ast_dummy_channel_alloc())) {
14155 ast_test_status_update(test, "Unable to create dummy channel\n");
14156 return AST_TEST_FAIL;
14157 }
14158
14159 if (!(vmu = find_user(NULL, testcontext, testmailbox)) &&
14160 !(vmu = find_or_create(testcontext, testmailbox))) {
14161 ast_test_status_update(test, "Cannot create vmu structure\n");
14162 chan = ast_channel_unref(chan);
14163 return AST_TEST_FAIL;
14164 }
14165
14166 populate_defaults(vmu);
14167
14168 ast_copy_string(vmu->email, "vm-info-test@example.net", sizeof(vmu->email));
14169 ast_copy_string(vmu->fullname, "Test Framework Mailbox", sizeof(vmu->fullname));
14170 ast_copy_string(vmu->pager, "vm-info-pager-test@example.net", sizeof(vmu->pager));
14171 ast_copy_string(vmu->language, "en", sizeof(vmu->language));
14172 ast_copy_string(vmu->zonetag, "central", sizeof(vmu->zonetag));
14173 ast_copy_string(vmu->locale, "en_US", sizeof(vmu->zonetag));
14174 ast_copy_string(vmu->password, "9876", sizeof(vmu->password));
14175
14176 for (test_counter = 0; test_counter < ARRAY_LEN(test_items); test_counter++) {
14177 ast_copy_string(vminfo_args, test_items[test_counter].vminfo_test_args, sizeof(vminfo_args));
14178 test_ret = acf_vm_info(chan, vminfo_cmd, vminfo_args, vminfo_buf, sizeof(vminfo_buf));
14179 if (strcmp(vminfo_buf, test_items[test_counter].vminfo_expected)) {
14180 ast_test_status_update(test, "VM_INFO respose was: '%s', but expected: '%s'\n", vminfo_buf, test_items[test_counter].vminfo_expected);
14181 res = AST_TEST_FAIL;
14182 }
14183 if (!(test_ret == test_items[test_counter].vminfo_ret)) {
14184 ast_test_status_update(test, "VM_INFO return code was: '%i', but expected '%i'\n", test_ret, test_items[test_counter].vminfo_ret);
14185 res = AST_TEST_FAIL;
14186 }
14187 }
14188
14189 chan = ast_channel_unref(chan);
14190 return res;
14191 }
14192 #endif
14193
14194 static int reload(void)
14195 {
14196 return load_config(1);
14197 }
14198
14199 static int unload_module(void)
14200 {
14201 int res;
14202
14203 res = ast_unregister_application(app);
14204 res |= ast_unregister_application(app2);
14205 res |= ast_unregister_application(app3);
14206 res |= ast_unregister_application(app4);
14207 res |= ast_unregister_application(playmsg_app);
14208 res |= ast_unregister_application(sayname_app);
14209 res |= ast_custom_function_unregister(&mailbox_exists_acf);
14210 res |= ast_custom_function_unregister(&vm_info_acf);
14211 res |= ast_manager_unregister("VoicemailUsersList");
14212 res |= ast_data_unregister(NULL);
14213 #ifdef TEST_FRAMEWORK
14214 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
14215 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
14216 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
14217 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
14218 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
14219 res |= AST_TEST_UNREGISTER(test_voicemail_vm_info);
14220 #endif
14221 ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
14222 ast_uninstall_vm_functions();
14223 #ifdef TEST_FRAMEWORK
14224 ast_uninstall_vm_test_functions();
14225 #endif
14226 ao2_ref(inprocess_container, -1);
14227
14228 if (poll_thread != AST_PTHREADT_NULL)
14229 stop_poll_thread();
14230
14231 mwi_subscription_tps = ast_taskprocessor_unreference(mwi_subscription_tps);
14232 ast_unload_realtime("voicemail");
14233 ast_unload_realtime("voicemail_data");
14234
14235 free_vm_users();
14236 free_vm_zones();
14237 return res;
14238 }
14239
14240 static int load_module(void)
14241 {
14242 int res;
14243 my_umask = umask(0);
14244 umask(my_umask);
14245
14246 if (!(inprocess_container = ao2_container_alloc(573, inprocess_hash_fn, inprocess_cmp_fn))) {
14247 return AST_MODULE_LOAD_DECLINE;
14248 }
14249
14250
14251 snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
14252
14253 if (!(mwi_subscription_tps = ast_taskprocessor_get("app_voicemail", 0))) {
14254 ast_log(AST_LOG_WARNING, "failed to reference mwi subscription taskprocessor. MWI will not work\n");
14255 }
14256
14257 if ((res = load_config(0)))
14258 return res;
14259
14260 res = ast_register_application_xml(app, vm_exec);
14261 res |= ast_register_application_xml(app2, vm_execmain);
14262 res |= ast_register_application_xml(app3, vm_box_exists);
14263 res |= ast_register_application_xml(app4, vmauthenticate);
14264 res |= ast_register_application_xml(playmsg_app, vm_playmsgexec);
14265 res |= ast_register_application_xml(sayname_app, vmsayname_exec);
14266 res |= ast_custom_function_register(&mailbox_exists_acf);
14267 res |= ast_custom_function_register(&vm_info_acf);
14268 res |= ast_manager_register_xml("VoicemailUsersList", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_list_voicemail_users);
14269 #ifdef TEST_FRAMEWORK
14270 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
14271 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
14272 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
14273 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
14274 res |= AST_TEST_REGISTER(test_voicemail_load_config);
14275 res |= AST_TEST_REGISTER(test_voicemail_vm_info);
14276 #endif
14277
14278 if (res)
14279 return res;
14280
14281 ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
14282 ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
14283
14284 ast_install_vm_functions(has_voicemail, inboxcount, inboxcount2, messagecount, sayname, msg_create_from_file,
14285 vm_index_to_foldername,
14286 vm_mailbox_snapshot_create, vm_mailbox_snapshot_destroy,
14287 vm_msg_move, vm_msg_remove, vm_msg_forward, vm_msg_play);
14288
14289 #ifdef TEST_FRAMEWORK
14290 ast_install_vm_test_functions(vm_test_create_user, vm_test_destroy_user);
14291 #endif
14292
14293 ast_realtime_require_field("voicemail", "uniqueid", RQ_UINTEGER3, 11, "password", RQ_CHAR, 10, SENTINEL);
14294 ast_realtime_require_field("voicemail_data", "filename", RQ_CHAR, 30, "duration", RQ_UINTEGER3, 5, SENTINEL);
14295
14296 return res;
14297 }
14298
14299 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
14300 {
14301 int cmd = 0;
14302 char destination[80] = "";
14303 int retries = 0;
14304
14305 if (!num) {
14306 ast_verb(3, "Destination number will be entered manually\n");
14307 while (retries < 3 && cmd != 't') {
14308 destination[1] = '\0';
14309 destination[0] = cmd = ast_play_and_wait(chan, "vm-enter-num-to-call");
14310 if (!cmd)
14311 destination[0] = cmd = ast_play_and_wait(chan, "vm-then-pound");
14312 if (!cmd)
14313 destination[0] = cmd = ast_play_and_wait(chan, "vm-star-cancel");
14314 if (!cmd) {
14315 cmd = ast_waitfordigit(chan, 6000);
14316 if (cmd)
14317 destination[0] = cmd;
14318 }
14319 if (!cmd) {
14320 retries++;
14321 } else {
14322
14323 if (cmd < 0)
14324 return 0;
14325 if (cmd == '*') {
14326 ast_verb(3, "User hit '*' to cancel outgoing call\n");
14327 return 0;
14328 }
14329 if ((cmd = ast_readstring(chan, destination + strlen(destination), sizeof(destination) - 1, 6000, 10000, "#")) < 0)
14330 retries++;
14331 else
14332 cmd = 't';
14333 }
14334 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", cmd, cmd);
14335 }
14336 if (retries >= 3) {
14337 return 0;
14338 }
14339
14340 } else {
14341 ast_verb(3, "Destination number is CID number '%s'\n", num);
14342 ast_copy_string(destination, num, sizeof(destination));
14343 }
14344
14345 if (!ast_strlen_zero(destination)) {
14346 if (destination[strlen(destination) -1 ] == '*')
14347 return 0;
14348 ast_verb(3, "Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, ast_channel_context(chan));
14349 ast_channel_exten_set(chan, destination);
14350 ast_channel_context_set(chan, outgoing_context);
14351 ast_channel_priority_set(chan, 0);
14352 return 9;
14353 }
14354 return 0;
14355 }
14356
14357
14358
14359
14360
14361
14362
14363
14364
14365
14366
14367
14368
14369
14370 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)
14371 {
14372 int res = 0;
14373 char filename[PATH_MAX];
14374 struct ast_config *msg_cfg = NULL;
14375 const char *origtime, *context;
14376 char *name, *num;
14377 int retries = 0;
14378 char *cid;
14379 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE, };
14380
14381 vms->starting = 0;
14382
14383 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
14384
14385
14386 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
14387 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
14388 msg_cfg = ast_config_load(filename, config_flags);
14389 DISPOSE(vms->curdir, vms->curmsg);
14390 if (!valid_config(msg_cfg)) {
14391 ast_log(AST_LOG_WARNING, "No message attribute file?!! (%s)\n", filename);
14392 return 0;
14393 }
14394
14395 if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
14396 ast_config_destroy(msg_cfg);
14397 return 0;
14398 }
14399
14400 cid = ast_strdupa(ast_variable_retrieve(msg_cfg, "message", "callerid"));
14401
14402 context = ast_variable_retrieve(msg_cfg, "message", "context");
14403 if (!strncasecmp("macro", context, 5))
14404 context = ast_variable_retrieve(msg_cfg, "message", "macrocontext");
14405 switch (option) {
14406 case 3:
14407 if (!res) {
14408 res = play_message_datetime(chan, vmu, origtime, filename);
14409 }
14410 if (!res) {
14411 res = play_message_callerid(chan, vms, cid, context, 0, 1);
14412 }
14413
14414 res = 't';
14415 break;
14416
14417 case 2:
14418
14419 if (ast_strlen_zero(cid))
14420 break;
14421
14422 ast_callerid_parse(cid, &name, &num);
14423 while ((res > -1) && (res != 't')) {
14424 switch (res) {
14425 case '1':
14426 if (num) {
14427
14428 res = dialout(chan, vmu, num, vmu->callback);
14429 if (res) {
14430 ast_config_destroy(msg_cfg);
14431 return 9;
14432 }
14433 } else {
14434 res = '2';
14435 }
14436 break;
14437
14438 case '2':
14439
14440 if (!ast_strlen_zero(vmu->dialout)) {
14441 res = dialout(chan, vmu, NULL, vmu->dialout);
14442 if (res) {
14443 ast_config_destroy(msg_cfg);
14444 return 9;
14445 }
14446 } else {
14447 ast_verb(3, "Caller can not specify callback number - no dialout context available\n");
14448 res = ast_play_and_wait(chan, "vm-sorry");
14449 }
14450 ast_config_destroy(msg_cfg);
14451 return res;
14452 case '*':
14453 res = 't';
14454 break;
14455 case '3':
14456 case '4':
14457 case '5':
14458 case '6':
14459 case '7':
14460 case '8':
14461 case '9':
14462 case '0':
14463
14464 res = ast_play_and_wait(chan, "vm-sorry");
14465 retries++;
14466 break;
14467 default:
14468 if (num) {
14469 ast_verb(3, "Confirm CID number '%s' is number to use for callback\n", num);
14470 res = ast_play_and_wait(chan, "vm-num-i-have");
14471 if (!res)
14472 res = play_message_callerid(chan, vms, num, vmu->context, 1, 1);
14473 if (!res)
14474 res = ast_play_and_wait(chan, "vm-tocallnum");
14475
14476 if (!ast_strlen_zero(vmu->dialout)) {
14477 if (!res)
14478 res = ast_play_and_wait(chan, "vm-calldiffnum");
14479 }
14480 } else {
14481 res = ast_play_and_wait(chan, "vm-nonumber");
14482 if (!ast_strlen_zero(vmu->dialout)) {
14483 if (!res)
14484 res = ast_play_and_wait(chan, "vm-toenternumber");
14485 }
14486 }
14487 if (!res) {
14488 res = ast_play_and_wait(chan, "vm-star-cancel");
14489 }
14490 if (!res) {
14491 res = ast_waitfordigit(chan, 6000);
14492 }
14493 if (!res) {
14494 retries++;
14495 if (retries > 3) {
14496 res = 't';
14497 }
14498 }
14499 ast_test_suite_event_notify("USERPRESS", "Message: User pressed %c\r\nDTMF: %c", res, res);
14500 break;
14501
14502 }
14503 if (res == 't')
14504 res = 0;
14505 else if (res == '*')
14506 res = -1;
14507 }
14508 break;
14509
14510 case 1:
14511
14512 if (ast_strlen_zero(cid))
14513 break;
14514
14515 ast_callerid_parse(cid, &name, &num);
14516 if (!num) {
14517 ast_verb(3, "No CID number available, no reply sent\n");
14518 if (!res)
14519 res = ast_play_and_wait(chan, "vm-nonumber");
14520 ast_config_destroy(msg_cfg);
14521 return res;
14522 } else {
14523 struct ast_vm_user vmu2;
14524 if (find_user(&vmu2, vmu->context, num)) {
14525 struct leave_vm_options leave_options;
14526 char mailbox[AST_MAX_EXTENSION * 2 + 2];
14527 snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
14528
14529 ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
14530
14531 memset(&leave_options, 0, sizeof(leave_options));
14532 leave_options.record_gain = record_gain;
14533 res = leave_voicemail(chan, mailbox, &leave_options);
14534 if (!res)
14535 res = 't';
14536 ast_config_destroy(msg_cfg);
14537 return res;
14538 } else {
14539
14540 ast_verb(3, "No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->context);
14541 ast_play_and_wait(chan, "vm-nobox");
14542 res = 't';
14543 ast_config_destroy(msg_cfg);
14544 return res;
14545 }
14546 }
14547 res = 0;
14548
14549 break;
14550 }
14551
14552 ast_config_destroy(msg_cfg);
14553
14554 #ifndef IMAP_STORAGE
14555 if (!res) {
14556 make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg);
14557 vms->heard[msg] = 1;
14558 res = wait_file(chan, vms, vms->fn);
14559 }
14560 #endif
14561 return res;
14562 }
14563
14564 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
14565 int outsidecaller, struct ast_vm_user *vmu, int *duration, int *sound_duration, const char *unlockdir,
14566 signed char record_gain, struct vm_state *vms, char *flag, const char *msg_id)
14567 {
14568
14569 int res = 0;
14570 int cmd = 0;
14571 int max_attempts = 3;
14572 int attempts = 0;
14573 int recorded = 0;
14574 int msg_exists = 0;
14575 signed char zero_gain = 0;
14576 char tempfile[PATH_MAX];
14577 char *acceptdtmf = "#";
14578 char *canceldtmf = "";
14579 int canceleddtmf = 0;
14580
14581
14582
14583
14584 if (duration == NULL) {
14585 ast_log(AST_LOG_WARNING, "Error play_record_review called without duration pointer\n");
14586 return -1;
14587 }
14588
14589 if (!outsidecaller)
14590 snprintf(tempfile, sizeof(tempfile), "%s.tmp", recordfile);
14591 else
14592 ast_copy_string(tempfile, recordfile, sizeof(tempfile));
14593
14594 cmd = '3';
14595
14596 while ((cmd >= 0) && (cmd != 't')) {
14597 switch (cmd) {
14598 case '1':
14599 if (!msg_exists) {
14600
14601 cmd = '3';
14602 break;
14603 } else {
14604
14605 ast_verb(3, "Saving message as is\n");
14606 if (!outsidecaller)
14607 ast_filerename(tempfile, recordfile, NULL);
14608 ast_stream_and_wait(chan, "vm-msgsaved", "");
14609 if (!outsidecaller) {
14610
14611 STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, *duration, vms, flag, msg_id);
14612 DISPOSE(recordfile, -1);
14613 }
14614 cmd = 't';
14615 return res;
14616 }
14617 case '2':
14618
14619 ast_verb(3, "Reviewing the message\n");
14620 cmd = ast_stream_and_wait(chan, tempfile, AST_DIGIT_ANY);
14621 break;
14622 case '3':
14623 msg_exists = 0;
14624
14625 if (recorded == 1)
14626 ast_verb(3, "Re-recording the message\n");
14627 else
14628 ast_verb(3, "Recording the message\n");
14629
14630 if (recorded && outsidecaller) {
14631 cmd = ast_play_and_wait(chan, INTRO);
14632 cmd = ast_play_and_wait(chan, "beep");
14633 }
14634 recorded = 1;
14635
14636 if (record_gain)
14637 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
14638 if (ast_test_flag(vmu, VM_OPERATOR))
14639 canceldtmf = "0";
14640 cmd = ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
14641 if (strchr(canceldtmf, cmd)) {
14642
14643 canceleddtmf = 1;
14644 }
14645 if (record_gain)
14646 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
14647 if (cmd == -1) {
14648
14649 if (!outsidecaller) {
14650
14651 ast_filedelete(tempfile, NULL);
14652 }
14653 return cmd;
14654 }
14655 if (cmd == '0') {
14656 break;
14657 } else if (cmd == '*') {
14658 break;
14659 #if 0
14660 } else if (vmu->review && sound_duration && (*sound_duration < 5)) {
14661
14662 ast_verb(3, "Message too short\n");
14663 cmd = ast_play_and_wait(chan, "vm-tooshort");
14664 cmd = ast_filedelete(tempfile, NULL);
14665 break;
14666 } else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
14667
14668 ast_verb(3, "Nothing recorded\n");
14669 cmd = ast_filedelete(tempfile, NULL);
14670 cmd = ast_play_and_wait(chan, "vm-nothingrecorded");
14671 if (!cmd)
14672 cmd = ast_play_and_wait(chan, "vm-speakup");
14673 break;
14674 #endif
14675 } else {
14676
14677 msg_exists = 1;
14678 cmd = 0;
14679 }
14680 break;
14681 case '4':
14682 if (outsidecaller) {
14683
14684 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
14685 ast_verb(3, "marking message as Urgent\n");
14686 res = ast_play_and_wait(chan, "vm-marked-urgent");
14687 strcpy(flag, "Urgent");
14688 } else if (flag) {
14689 ast_verb(3, "UNmarking message as Urgent\n");
14690 res = ast_play_and_wait(chan, "vm-marked-nonurgent");
14691 strcpy(flag, "");
14692 } else {
14693 ast_play_and_wait(chan, "vm-sorry");
14694 }
14695 cmd = 0;
14696 } else {
14697 cmd = ast_play_and_wait(chan, "vm-sorry");
14698 }
14699 break;
14700 case '5':
14701 case '6':
14702 case '7':
14703 case '8':
14704 case '9':
14705 case '*':
14706 case '#':
14707 cmd = ast_play_and_wait(chan, "vm-sorry");
14708 break;
14709 #if 0
14710
14711
14712 case '*':
14713
14714 cmd = ast_play_and_wait(chan, "vm-deleted");
14715 cmd = ast_filedelete(tempfile, NULL);
14716 if (outsidecaller) {
14717 res = vm_exec(chan, NULL);
14718 return res;
14719 }
14720 else
14721 return 1;
14722 #endif
14723 case '0':
14724 if (!ast_test_flag(vmu, VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
14725 cmd = ast_play_and_wait(chan, "vm-sorry");
14726 break;
14727 }
14728 if (msg_exists || recorded) {
14729 cmd = ast_play_and_wait(chan, "vm-saveoper");
14730 if (!cmd)
14731 cmd = ast_waitfordigit(chan, 3000);
14732 if (cmd == '1') {
14733 ast_filerename(tempfile, recordfile, NULL);
14734 ast_play_and_wait(chan, "vm-msgsaved");
14735 cmd = '0';
14736 } else if (cmd == '4') {
14737 if (flag) {
14738 ast_play_and_wait(chan, "vm-marked-urgent");
14739 strcpy(flag, "Urgent");
14740 }
14741 ast_play_and_wait(chan, "vm-msgsaved");
14742 cmd = '0';
14743 } else {
14744 ast_play_and_wait(chan, "vm-deleted");
14745 DELETE(tempfile, -1, tempfile, vmu);
14746 cmd = '0';
14747 }
14748 }
14749 return cmd;
14750 default:
14751
14752
14753
14754 if (outsidecaller && !ast_test_flag(vmu, VM_REVIEW))
14755 return cmd;
14756 if (msg_exists) {
14757 cmd = ast_play_and_wait(chan, "vm-review");
14758 if (!cmd && outsidecaller) {
14759 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag, "Urgent"))) {
14760 cmd = ast_play_and_wait(chan, "vm-review-urgent");
14761 } else if (flag) {
14762 cmd = ast_play_and_wait(chan, "vm-review-nonurgent");
14763 }
14764 }
14765 } else {
14766 cmd = ast_play_and_wait(chan, "vm-torerecord");
14767 if (!cmd)
14768 cmd = ast_waitfordigit(chan, 600);
14769 }
14770
14771 if (!cmd && outsidecaller && ast_test_flag(vmu, VM_OPERATOR)) {
14772 cmd = ast_play_and_wait(chan, "vm-reachoper");
14773 if (!cmd)
14774 cmd = ast_waitfordigit(chan, 600);
14775 }
14776 #if 0
14777 if (!cmd)
14778 cmd = ast_play_and_wait(chan, "vm-tocancelmsg");
14779 #endif
14780 if (!cmd)
14781 cmd = ast_waitfordigit(chan, 6000);
14782 if (!cmd) {
14783 attempts++;
14784 }
14785 if (attempts > max_attempts) {
14786 cmd = 't';
14787 }
14788 }
14789 }
14790 if (!outsidecaller && (cmd == -1 || cmd == 't')) {
14791
14792 ast_filedelete(tempfile, NULL);
14793 }
14794
14795 if (cmd != 't' && outsidecaller)
14796 ast_play_and_wait(chan, "vm-goodbye");
14797
14798 return cmd;
14799 }
14800
14801 static struct ast_vm_msg_snapshot *vm_msg_snapshot_alloc(void)
14802 {
14803 struct ast_vm_msg_snapshot *msg_snapshot;
14804
14805 if (!(msg_snapshot = ast_calloc(1, sizeof(*msg_snapshot)))) {
14806 return NULL;
14807 }
14808
14809 if (ast_string_field_init(msg_snapshot, 512)) {
14810 ast_free(msg_snapshot);
14811 return NULL;
14812 }
14813
14814 return msg_snapshot;
14815 }
14816
14817 static struct ast_vm_msg_snapshot *vm_msg_snapshot_destroy(struct ast_vm_msg_snapshot *msg_snapshot)
14818 {
14819 ast_string_field_free_memory(msg_snapshot);
14820 ast_free(msg_snapshot);
14821
14822 return NULL;
14823 }
14824
14825 #ifdef TEST_FRAMEWORK
14826
14827 static int vm_test_destroy_user(const char *context, const char *mailbox)
14828 {
14829 struct ast_vm_user *vmu;
14830
14831 AST_LIST_LOCK(&users);
14832 AST_LIST_TRAVERSE_SAFE_BEGIN(&users, vmu, list) {
14833 if (!strcmp(context, vmu->context)
14834 && !strcmp(mailbox, vmu->mailbox)) {
14835 AST_LIST_REMOVE_CURRENT(list);
14836 ast_free(vmu);
14837 break;
14838 }
14839 }
14840 AST_LIST_TRAVERSE_SAFE_END
14841 AST_LIST_UNLOCK(&users);
14842 return 0;
14843 }
14844
14845 static int vm_test_create_user(const char *context, const char *mailbox)
14846 {
14847 struct ast_vm_user *vmu;
14848
14849 if (!(vmu = find_or_create(context, mailbox))) {
14850 return -1;
14851 }
14852 populate_defaults(vmu);
14853 return 0;
14854 }
14855
14856 #endif
14857
14858
14859
14860
14861
14862
14863
14864
14865
14866
14867
14868
14869 static int vm_msg_snapshot_create(struct ast_vm_user *vmu,
14870 struct vm_state *vms,
14871 struct ast_vm_mailbox_snapshot *mailbox_snapshot,
14872 int snapshot_index,
14873 int mailbox_index,
14874 int descending,
14875 enum ast_vm_snapshot_sort_val sort_val)
14876 {
14877 struct ast_vm_msg_snapshot *msg_snapshot;
14878 struct ast_vm_msg_snapshot *msg_snapshot_tmp;
14879 struct ast_config *msg_cfg;
14880 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
14881 char filename[PATH_MAX];
14882 const char *value;
14883
14884 for (vms->curmsg = 0; vms->curmsg <= vms->lastmsg; vms->curmsg++) {
14885 int inserted = 0;
14886
14887 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
14888 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
14889 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
14890 msg_cfg = ast_config_load(filename, config_flags);
14891 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
14892 DISPOSE(vms->curdir, vms->curmsg);
14893 continue;
14894 }
14895
14896
14897 if (!(msg_snapshot = vm_msg_snapshot_alloc())) {
14898 ast_config_destroy(msg_cfg);
14899 return -1;
14900 }
14901
14902
14903 if ((value = ast_variable_retrieve(msg_cfg, "message", "msg_id"))) {
14904 ast_string_field_set(msg_snapshot, msg_id, value);
14905 } else {
14906
14907
14908
14909
14910 char id[MSG_ID_LEN];
14911 if (!(add_message_id(msg_cfg, vms->curdir, vms->curmsg,
14912 filename, id, sizeof(id), vmu, mailbox_index))) {
14913 ast_string_field_set(msg_snapshot, msg_id, id);
14914 } else {
14915 ast_log(LOG_WARNING, "Unable to create a message ID for message %s/%d\n", vms->curdir, vms->curmsg);
14916 }
14917 }
14918 if ((value = ast_variable_retrieve(msg_cfg, "message", "callerid"))) {
14919 ast_string_field_set(msg_snapshot, callerid, value);
14920 }
14921 if ((value = ast_variable_retrieve(msg_cfg, "message", "callerchan"))) {
14922 ast_string_field_set(msg_snapshot, callerchan, value);
14923 }
14924 if ((value = ast_variable_retrieve(msg_cfg, "message", "exten"))) {
14925 ast_string_field_set(msg_snapshot, exten, value);
14926 }
14927 if ((value = ast_variable_retrieve(msg_cfg, "message", "origdate"))) {
14928 ast_string_field_set(msg_snapshot, origdate, value);
14929 }
14930 if ((value = ast_variable_retrieve(msg_cfg, "message", "origtime"))) {
14931 ast_string_field_set(msg_snapshot, origtime, value);
14932 }
14933 if ((value = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
14934 ast_string_field_set(msg_snapshot, duration, value);
14935 }
14936 if ((value = ast_variable_retrieve(msg_cfg, "message", "flag"))) {
14937 ast_string_field_set(msg_snapshot, flag, value);
14938 }
14939 msg_snapshot->msg_number = vms->curmsg;
14940 ast_string_field_set(msg_snapshot, folder_name, mailbox_folders[mailbox_index]);
14941
14942
14943 switch (sort_val) {
14944 default:
14945 case AST_VM_SNAPSHOT_SORT_BY_ID:
14946 if (descending) {
14947 AST_LIST_INSERT_HEAD(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg);
14948 } else {
14949 AST_LIST_INSERT_TAIL(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg);
14950 }
14951 inserted = 1;
14952 break;
14953 case AST_VM_SNAPSHOT_SORT_BY_TIME:
14954 AST_LIST_TRAVERSE_SAFE_BEGIN(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot_tmp, msg) {
14955 int val = strcmp(msg_snapshot->origtime, msg_snapshot_tmp->origtime);
14956 if (descending && val >= 0) {
14957 AST_LIST_INSERT_BEFORE_CURRENT(msg_snapshot, msg);
14958 inserted = 1;
14959 break;
14960 } else if (!descending && val <= 0) {
14961 AST_LIST_INSERT_BEFORE_CURRENT(msg_snapshot, msg);
14962 inserted = 1;
14963 break;
14964 }
14965 }
14966 AST_LIST_TRAVERSE_SAFE_END;
14967 break;
14968 }
14969
14970 if (!inserted) {
14971 AST_LIST_INSERT_TAIL(&mailbox_snapshot->snapshots[snapshot_index], msg_snapshot, msg);
14972 }
14973
14974 mailbox_snapshot->total_msg_num++;
14975
14976
14977 ast_config_destroy(msg_cfg);
14978 DISPOSE(vms->curdir, vms->curmsg);
14979 }
14980
14981 return 0;
14982 }
14983
14984 static struct ast_vm_mailbox_snapshot *vm_mailbox_snapshot_create(const char *mailbox,
14985 const char *context,
14986 const char *folder,
14987 int descending,
14988 enum ast_vm_snapshot_sort_val sort_val,
14989 int combine_INBOX_and_OLD)
14990 {
14991 struct ast_vm_mailbox_snapshot *mailbox_snapshot;
14992 struct vm_state vms;
14993 struct ast_vm_user *vmu = NULL, vmus;
14994 int res;
14995 int i;
14996 int this_index_only = -1;
14997 int open = 0;
14998 int inbox_index = get_folder_by_name("INBOX");
14999 int old_index = get_folder_by_name("Old");
15000 int urgent_index = get_folder_by_name("Urgent");
15001
15002 if (ast_strlen_zero(mailbox)) {
15003 ast_log(LOG_WARNING, "Cannot create a mailbox snapshot since no mailbox was specified\n");
15004 return NULL;
15005 }
15006
15007 memset(&vmus, 0, sizeof(vmus));
15008
15009 if (!(ast_strlen_zero(folder))) {
15010
15011 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
15012 if (!strcasecmp(mailbox_folders[i], folder)) {
15013 this_index_only = i;
15014 break;
15015 }
15016 }
15017 if (this_index_only == -1) {
15018
15019 return NULL;
15020 }
15021 }
15022
15023 if (!(vmu = find_user(&vmus, context, mailbox))) {
15024 ast_log(AST_LOG_WARNING, "Failed to create mailbox snapshot for unknown voicemail user %s@%s\n", mailbox, context);
15025 return NULL;
15026 }
15027
15028 if (!(mailbox_snapshot = ast_calloc(1, sizeof(*mailbox_snapshot)))) {
15029 ast_log(AST_LOG_ERROR, "Failed to allocate memory for mailbox snapshot\n");
15030 return NULL;
15031 }
15032
15033 if (!(mailbox_snapshot->snapshots = ast_calloc(ARRAY_LEN(mailbox_folders), sizeof(*mailbox_snapshot->snapshots)))) {
15034 ast_free(mailbox_snapshot);
15035 return NULL;
15036 }
15037
15038 mailbox_snapshot->folders = ARRAY_LEN(mailbox_folders);
15039
15040 for (i = 0; i < mailbox_snapshot->folders; i++) {
15041 int msg_folder_index = i;
15042
15043
15044
15045
15046
15047
15048 if (!(this_index_only == -1 || this_index_only == i || (this_index_only == inbox_index && combine_INBOX_and_OLD && (i == old_index || i == urgent_index)))) {
15049 continue;
15050 }
15051
15052
15053 if (combine_INBOX_and_OLD && (i == old_index || i == urgent_index)) {
15054 msg_folder_index = inbox_index;
15055 }
15056
15057 memset(&vms, 0, sizeof(vms));
15058 ast_copy_string(vms.username, mailbox, sizeof(vms.username));
15059 vms.lastmsg = -1;
15060 open = 0;
15061
15062
15063 if ((res = open_mailbox(&vms, vmu, i)) < 0) {
15064 ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
15065 goto snapshot_cleanup;
15066 }
15067 open = 1;
15068
15069
15070 if (vms.lastmsg != -1) {
15071 if ((vm_msg_snapshot_create(vmu, &vms, mailbox_snapshot, msg_folder_index, i, descending, sort_val))) {
15072 ast_log(LOG_WARNING, "Failed to create msg snapshots for %s@%s\n", mailbox, context);
15073 goto snapshot_cleanup;
15074 }
15075 }
15076
15077
15078 if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
15079 goto snapshot_cleanup;
15080 }
15081 open = 0;
15082 }
15083
15084 snapshot_cleanup:
15085 if (vmu && open) {
15086 close_mailbox(&vms, vmu);
15087 }
15088
15089 #ifdef IMAP_STORAGE
15090 if (vmu) {
15091 vmstate_delete(&vms);
15092 }
15093 #endif
15094
15095 return mailbox_snapshot;
15096 }
15097
15098 static struct ast_vm_mailbox_snapshot *vm_mailbox_snapshot_destroy(struct ast_vm_mailbox_snapshot *mailbox_snapshot)
15099 {
15100 int i;
15101 struct ast_vm_msg_snapshot *msg_snapshot;
15102
15103 for (i = 0; i < mailbox_snapshot->folders; i++) {
15104 while ((msg_snapshot = AST_LIST_REMOVE_HEAD(&mailbox_snapshot->snapshots[i], msg))) {
15105 msg_snapshot = vm_msg_snapshot_destroy(msg_snapshot);
15106 }
15107 }
15108 ast_free(mailbox_snapshot->snapshots);
15109 ast_free(mailbox_snapshot);
15110 return NULL;
15111 }
15112
15113
15114
15115
15116
15117
15118
15119
15120
15121
15122
15123
15124
15125
15126
15127
15128
15129
15130
15131 static int message_range_and_existence_check(struct vm_state *vms, const char *msg_ids [], size_t num_msgs, int *msg_nums, struct ast_vm_user *vmu)
15132 {
15133 int i;
15134 int res = 0;
15135 for (i = 0; i < num_msgs; ++i) {
15136 const char *msg_id = msg_ids[i];
15137 int found = 0;
15138 for (vms->curmsg = 0; vms->curmsg <= vms->lastmsg; vms->curmsg++) {
15139 const char *other_msg_id;
15140 char filename[PATH_MAX];
15141 struct ast_config *msg_cfg;
15142 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
15143
15144 make_file(vms->fn, sizeof(vms->fn), vms->curdir, vms->curmsg);
15145 snprintf(filename, sizeof(filename), "%s.txt", vms->fn);
15146 RETRIEVE(vms->curdir, vms->curmsg, vmu->mailbox, vmu->context);
15147 msg_cfg = ast_config_load(filename, config_flags);
15148 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
15149 DISPOSE(vms->curdir, vms->curmsg);
15150 res = -1;
15151 goto done;
15152 }
15153
15154 other_msg_id = ast_variable_retrieve(msg_cfg, "message", "msg_id");
15155
15156 if (!ast_strlen_zero(other_msg_id) && !strcmp(other_msg_id, msg_id)) {
15157
15158
15159
15160 found = 1;
15161 msg_nums[i] = vms->curmsg;
15162 ast_config_destroy(msg_cfg);
15163 DISPOSE(vms->curdir, vms->curmsg);
15164 break;
15165 }
15166 ast_config_destroy(msg_cfg);
15167 DISPOSE(vms->curdir, vms->curmsg);
15168 }
15169 if (!found) {
15170
15171 res = -1;
15172 goto done;
15173 }
15174 }
15175
15176 done:
15177 return res;
15178 }
15179
15180 static void notify_new_state(struct ast_vm_user *vmu)
15181 {
15182 int new = 0, old = 0, urgent = 0;
15183 char ext_context[1024];
15184
15185 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
15186 run_externnotify(vmu->context, vmu->mailbox, NULL);
15187 ast_app_inboxcount2(ext_context, &urgent, &new, &old);
15188 queue_mwi_event(ext_context, urgent, new, old);
15189 }
15190
15191 static int vm_msg_forward(const char *from_mailbox,
15192 const char *from_context,
15193 const char *from_folder,
15194 const char *to_mailbox,
15195 const char *to_context,
15196 const char *to_folder,
15197 size_t num_msgs,
15198 const char *msg_ids [],
15199 int delete_old)
15200 {
15201 struct vm_state from_vms;
15202 struct ast_vm_user *vmu = NULL, vmus;
15203 struct ast_vm_user *to_vmu = NULL, to_vmus;
15204 struct ast_config *msg_cfg;
15205 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
15206 char filename[PATH_MAX];
15207 int from_folder_index;
15208 int open = 0;
15209 int res = 0;
15210 int i;
15211 int *msg_nums;
15212
15213 if (ast_strlen_zero(from_mailbox) || ast_strlen_zero(to_mailbox)) {
15214 ast_log(LOG_WARNING, "Cannot forward message because either the from or to mailbox was not specified\n");
15215 return -1;
15216 }
15217
15218 if (!num_msgs) {
15219 ast_log(LOG_WARNING, "Invalid number of messages specified to forward: %zu\n", num_msgs);
15220 return -1;
15221 }
15222
15223 if (ast_strlen_zero(from_folder) || ast_strlen_zero(to_folder)) {
15224 ast_log(LOG_WARNING, "Cannot forward message because the from_folder or to_folder was not specified\n");
15225 return -1;
15226 }
15227
15228 memset(&vmus, 0, sizeof(vmus));
15229 memset(&to_vmus, 0, sizeof(to_vmus));
15230 memset(&from_vms, 0, sizeof(from_vms));
15231
15232 from_folder_index = get_folder_by_name(from_folder);
15233 if (from_folder_index == -1) {
15234 return -1;
15235 }
15236
15237 if (get_folder_by_name(to_folder) == -1) {
15238 return -1;
15239 }
15240
15241 if (!(vmu = find_user(&vmus, from_context, from_mailbox))) {
15242 ast_log(LOG_WARNING, "Can't find voicemail user to forward from (%s@%s)\n", from_mailbox, from_context);
15243 return -1;
15244 }
15245
15246 if (!(to_vmu = find_user(&to_vmus, to_context, to_mailbox))) {
15247 ast_log(LOG_WARNING, "Can't find voicemail user to forward to (%s@%s)\n", to_mailbox, to_context);
15248 return -1;
15249 }
15250
15251 ast_copy_string(from_vms.username, from_mailbox, sizeof(from_vms.username));
15252 from_vms.lastmsg = -1;
15253 open = 0;
15254
15255
15256 if ((res = open_mailbox(&from_vms, vmu, from_folder_index)) < 0) {
15257 ast_log(LOG_WARNING, "Could not open mailbox %s\n", from_mailbox);
15258 res = -1;
15259 goto vm_forward_cleanup;
15260 }
15261
15262 open = 1;
15263
15264 if ((from_vms.lastmsg + 1) < num_msgs) {
15265 ast_log(LOG_WARNING, "Folder %s has less than %zu messages\n", from_folder, num_msgs);
15266 res = -1;
15267 goto vm_forward_cleanup;
15268 }
15269
15270 msg_nums = ast_alloca(sizeof(int) * num_msgs);
15271
15272 if ((res = message_range_and_existence_check(&from_vms, msg_ids, num_msgs, msg_nums, vmu) < 0)) {
15273 goto vm_forward_cleanup;
15274 }
15275
15276
15277 for (i = 0; i < num_msgs; i++) {
15278 int cur_msg = msg_nums[i];
15279 int duration = 0;
15280 const char *value;
15281
15282 make_file(from_vms.fn, sizeof(from_vms.fn), from_vms.curdir, cur_msg);
15283 snprintf(filename, sizeof(filename), "%s.txt", from_vms.fn);
15284 RETRIEVE(from_vms.curdir, cur_msg, vmu->mailbox, vmu->context);
15285 msg_cfg = ast_config_load(filename, config_flags);
15286
15287
15288
15289
15290 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
15291 DISPOSE(from_vms.curdir, cur_msg);
15292 continue;
15293 }
15294 if ((value = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
15295 duration = atoi(value);
15296 }
15297
15298 copy_message(NULL, vmu, from_folder_index, cur_msg, duration, to_vmu, vmfmts, from_vms.curdir, "", to_folder);
15299
15300 if (delete_old) {
15301 from_vms.deleted[cur_msg] = 1;
15302 }
15303 ast_config_destroy(msg_cfg);
15304 DISPOSE(from_vms.curdir, cur_msg);
15305 }
15306
15307
15308 if ((res = close_mailbox(&from_vms, vmu) == ERROR_LOCK_PATH)) {
15309 res = -1;
15310 goto vm_forward_cleanup;
15311 }
15312 open = 0;
15313
15314 vm_forward_cleanup:
15315 if (vmu && open) {
15316 close_mailbox(&from_vms, vmu);
15317 }
15318 #ifdef IMAP_STORAGE
15319 if (vmu) {
15320 vmstate_delete(&from_vms);
15321 }
15322 #endif
15323
15324 if (!res) {
15325 notify_new_state(to_vmu);
15326 }
15327
15328 return res;
15329 }
15330
15331 static int vm_msg_move(const char *mailbox,
15332 const char *context,
15333 size_t num_msgs,
15334 const char *oldfolder,
15335 const char *old_msg_ids [],
15336 const char *newfolder)
15337 {
15338 struct vm_state vms;
15339 struct ast_vm_user *vmu = NULL, vmus;
15340 int old_folder_index;
15341 int new_folder_index;
15342 int open = 0;
15343 int res = 0;
15344 int i;
15345 int *old_msg_nums;
15346
15347 if (ast_strlen_zero(mailbox)) {
15348 ast_log(LOG_WARNING, "Cannot move message because no mailbox was specified\n");
15349 return -1;
15350 }
15351
15352 if (!num_msgs) {
15353 ast_log(LOG_WARNING, "Invalid number of messages specified to move: %zu\n", num_msgs);
15354 return -1;
15355 }
15356
15357 if (ast_strlen_zero(oldfolder) || ast_strlen_zero(newfolder)) {
15358 ast_log(LOG_WARNING, "Cannot move message because either oldfolder or newfolder was not specified\n");
15359 return -1;
15360 }
15361
15362 old_folder_index = get_folder_by_name(oldfolder);
15363 new_folder_index = get_folder_by_name(newfolder);
15364
15365 memset(&vmus, 0, sizeof(vmus));
15366 memset(&vms, 0, sizeof(vms));
15367
15368 if (old_folder_index == -1 || new_folder_index == -1) {
15369 return -1;
15370 }
15371
15372 if (!(vmu = find_user(&vmus, context, mailbox))) {
15373 return -1;
15374 }
15375
15376 ast_copy_string(vms.username, mailbox, sizeof(vms.username));
15377 vms.lastmsg = -1;
15378 open = 0;
15379
15380
15381 if ((res = open_mailbox(&vms, vmu, old_folder_index)) < 0) {
15382 ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
15383 res = -1;
15384 goto vm_move_cleanup;
15385 }
15386
15387 open = 1;
15388
15389 if ((vms.lastmsg + 1) < num_msgs) {
15390 ast_log(LOG_WARNING, "Folder %s has less than %zu messages\n", oldfolder, num_msgs);
15391 res = -1;
15392 goto vm_move_cleanup;
15393 }
15394
15395 old_msg_nums = ast_alloca(sizeof(int) * num_msgs);
15396
15397 if ((res = message_range_and_existence_check(&vms, old_msg_ids, num_msgs, old_msg_nums, vmu)) < 0) {
15398 goto vm_move_cleanup;
15399 }
15400
15401
15402 for (i = 0; i < num_msgs; ++i) {
15403 if (save_to_folder(vmu, &vms, old_msg_nums[i], new_folder_index, NULL, 0)) {
15404 res = -1;
15405 goto vm_move_cleanup;
15406 }
15407 vms.deleted[old_msg_nums[i]] = 1;
15408 }
15409
15410
15411 if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
15412 res = -1;
15413 goto vm_move_cleanup;
15414 }
15415 open = 0;
15416
15417 vm_move_cleanup:
15418 if (vmu && open) {
15419 close_mailbox(&vms, vmu);
15420 }
15421 #ifdef IMAP_STORAGE
15422 if (vmu) {
15423 vmstate_delete(&vms);
15424 }
15425 #endif
15426
15427 if (!res) {
15428 notify_new_state(vmu);
15429 }
15430
15431 return res;
15432 }
15433
15434 static int vm_msg_remove(const char *mailbox,
15435 const char *context,
15436 size_t num_msgs,
15437 const char *folder,
15438 const char *msgs[])
15439 {
15440 struct vm_state vms;
15441 struct ast_vm_user *vmu = NULL, vmus;
15442 int folder_index;
15443 int open = 0;
15444 int res = 0;
15445 int i;
15446 int *msg_nums;
15447
15448 if (ast_strlen_zero(mailbox)) {
15449 ast_log(LOG_WARNING, "Cannot remove message because no mailbox was specified\n");
15450 return -1;
15451 }
15452
15453 if (!num_msgs) {
15454 ast_log(LOG_WARNING, "Invalid number of messages specified to remove: %zu\n", num_msgs);
15455 return -1;
15456 }
15457
15458 if (ast_strlen_zero(folder)) {
15459 ast_log(LOG_WARNING, "Cannot remove message because no folder was specified\n");
15460 return -1;
15461 }
15462
15463 memset(&vmus, 0, sizeof(vmus));
15464 memset(&vms, 0, sizeof(vms));
15465
15466 folder_index = get_folder_by_name(folder);
15467 if (folder_index == -1) {
15468 ast_log(LOG_WARNING, "Could not remove msgs from unknown folder %s\n", folder);
15469 return -1;
15470 }
15471
15472 if (!(vmu = find_user(&vmus, context, mailbox))) {
15473 ast_log(LOG_WARNING, "Can't find voicemail user to remove msg from (%s@%s)\n", mailbox, context);
15474 return -1;
15475 }
15476
15477 ast_copy_string(vms.username, mailbox, sizeof(vms.username));
15478 vms.lastmsg = -1;
15479 open = 0;
15480
15481
15482 if ((res = open_mailbox(&vms, vmu, folder_index)) < 0) {
15483 ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
15484 res = -1;
15485 goto vm_remove_cleanup;
15486 }
15487
15488 open = 1;
15489
15490 if ((vms.lastmsg + 1) < num_msgs) {
15491 ast_log(LOG_WARNING, "Folder %s has less than %zu messages\n", folder, num_msgs);
15492 res = -1;
15493 goto vm_remove_cleanup;
15494 }
15495
15496 msg_nums = ast_alloca(sizeof(int) * num_msgs);
15497
15498 if ((res = message_range_and_existence_check(&vms, msgs, num_msgs, msg_nums, vmu)) < 0) {
15499 goto vm_remove_cleanup;
15500 }
15501
15502 for (i = 0; i < num_msgs; i++) {
15503 vms.deleted[msg_nums[i]] = 1;
15504 }
15505
15506
15507 if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
15508 res = -1;
15509 ast_log(AST_LOG_ERROR, "Failed to close mailbox folder %s while removing msgs\n", folder);
15510 goto vm_remove_cleanup;
15511 }
15512 open = 0;
15513
15514 vm_remove_cleanup:
15515 if (vmu && open) {
15516 close_mailbox(&vms, vmu);
15517 }
15518 #ifdef IMAP_STORAGE
15519 if (vmu) {
15520 vmstate_delete(&vms);
15521 }
15522 #endif
15523
15524 if (!res) {
15525 notify_new_state(vmu);
15526 }
15527
15528 return res;
15529 }
15530
15531 static int vm_msg_play(struct ast_channel *chan,
15532 const char *mailbox,
15533 const char *context,
15534 const char *folder,
15535 const char *msg_id,
15536 ast_vm_msg_play_cb cb)
15537 {
15538 struct vm_state vms;
15539 struct ast_vm_user *vmu = NULL, vmus;
15540 int res = 0;
15541 int open = 0;
15542 int i;
15543 char filename[PATH_MAX];
15544 struct ast_config *msg_cfg;
15545 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
15546 int duration = 0;
15547 const char *value;
15548
15549 if (ast_strlen_zero(mailbox)) {
15550 ast_log(LOG_WARNING, "Cannot play message because no mailbox was specified\n");
15551 return -1;
15552 }
15553
15554 if (ast_strlen_zero(folder)) {
15555 ast_log(LOG_WARNING, "Cannot play message because no folder was specified\n");
15556 return -1;
15557 }
15558
15559 if (ast_strlen_zero(msg_id)) {
15560 ast_log(LOG_WARNING, "Cannot play message because no message number was specified\n");
15561 return -1;
15562 }
15563
15564 memset(&vmus, 0, sizeof(vmus));
15565 memset(&vms, 0, sizeof(vms));
15566
15567 if (ast_strlen_zero(context)) {
15568 context = "default";
15569 }
15570
15571 if (!(vmu = find_user(&vmus, context, mailbox))) {
15572 return -1;
15573 }
15574
15575 i = get_folder_by_name(folder);
15576 ast_copy_string(vms.username, mailbox, sizeof(vms.username));
15577 vms.lastmsg = -1;
15578 if ((res = open_mailbox(&vms, vmu, i)) < 0) {
15579 ast_log(LOG_WARNING, "Could not open mailbox %s\n", mailbox);
15580 goto play2_msg_cleanup;
15581 }
15582 open = 1;
15583
15584 if (message_range_and_existence_check(&vms, &msg_id, 1, &vms.curmsg, vmu)) {
15585 res = -1;
15586 goto play2_msg_cleanup;
15587 }
15588
15589
15590 make_file(vms.fn, sizeof(vms.fn), vms.curdir, vms.curmsg);
15591 snprintf(filename, sizeof(filename), "%s.txt", vms.fn);
15592 RETRIEVE(vms.curdir, vms.curmsg, vmu->mailbox, vmu->context);
15593
15594 msg_cfg = ast_config_load(filename, config_flags);
15595 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
15596 DISPOSE(vms.curdir, vms.curmsg);
15597 res = -1;
15598 goto play2_msg_cleanup;
15599 }
15600 if ((value = ast_variable_retrieve(msg_cfg, "message", "duration"))) {
15601 duration = atoi(value);
15602 }
15603 ast_config_destroy(msg_cfg);
15604
15605 #ifdef IMAP_STORAGE
15606
15607
15608
15609 if (!ast_strlen_zero(vms.introfn) && ast_fileexists(vms.introfn, NULL, NULL) > 0) {
15610 wait_file(chan, &vms, vms.introfn);
15611 }
15612 #endif
15613 if (cb) {
15614 cb(chan, vms.fn, duration);
15615 } else if ((wait_file(chan, &vms, vms.fn)) < 0) {
15616 ast_log(AST_LOG_WARNING, "Playback of message %s failed\n", vms.fn);
15617 } else {
15618 res = 0;
15619 }
15620
15621 vms.heard[vms.curmsg] = 1;
15622
15623
15624 DISPOSE(vms.curdir, vms.curmsg);
15625
15626 play2_msg_cleanup:
15627 if (vmu && open) {
15628 close_mailbox(&vms, vmu);
15629 }
15630
15631 #ifdef IMAP_STORAGE
15632 if (vmu) {
15633 vmstate_delete(&vms);
15634 }
15635 #endif
15636
15637 if (!res) {
15638 notify_new_state(vmu);
15639 }
15640
15641 return res;
15642 }
15643
15644
15645
15646
15647
15648 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
15649 .load = load_module,
15650 .unload = unload_module,
15651 .reload = reload,
15652 .nonoptreq = "res_adsi,res_smdi",
15653 );